hridoy-ultimate 9.0.0 → 9.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +346 -69
  2. package/{docs/UPSTREAM_API_DOCS.md → DOCS.md} +3 -3
  3. package/README.md +536 -161
  4. package/func/checkUpdate.js +1 -0
  5. package/index.d.ts +13 -74
  6. package/index.js +0 -6
  7. package/module/config.js +2 -5
  8. package/module/login.js +1 -2
  9. package/module/loginHelper.js +9 -41
  10. package/module/options.js +6 -6
  11. package/package.json +44 -39
  12. package/src/api/action/logout.js +0 -19
  13. package/src/api/messaging/sendMessage.js +1 -1
  14. package/src/api/messaging/sessionGuard.js +8 -0
  15. package/src/api/messaging/setMessageReaction.js +2 -7
  16. package/src/api/socket/core/connectMqtt.js +72 -99
  17. package/src/api/socket/core/emitAuth.js +17 -9
  18. package/src/api/socket/e2ee/index.js +15 -33
  19. package/src/api/socket/e2ee/native/NOTICE.md +2 -2
  20. package/src/api/socket/e2ee/native/lib/index.mjs +1 -2
  21. package/src/api/socket/e2ee/native/nativeMediaBridge.js +4 -4
  22. package/src/api/socket/listenE2EE.js +1 -3
  23. package/src/api/socket/listenMqtt.js +60 -67
  24. package/src/utils/antiSuspension.js +3 -3
  25. package/src/utils/fingerprint.js +35 -16
  26. package/src/utils/headers.js +1 -1
  27. package/src/utils/versionCheck.js +47 -0
  28. package/LICENSE +0 -23
  29. package/MERGE_REPORT.md +0 -54
  30. package/THIRD_PARTY_NOTICES.md +0 -36
  31. package/docs/TEST_RESULTS.md +0 -68
  32. package/scripts/run-tests.js +0 -19
  33. package/scripts/syntax-check.js +0 -22
  34. package/src/api/socket/core/lifecycle.js +0 -117
  35. package/src/api/socket/e2ee/proto/proto-writer.ts +0 -76
  36. package/src/utils/typingIndicator.js +0 -202
  37. package/test/helpers/stub-modules.js +0 -122
  38. package/test/integration/logout.test.js +0 -69
  39. package/test/integration/mqtt-lifecycle.test.js +0 -195
  40. package/test/integration/package.test.js +0 -116
  41. package/test/integration/typing-wiring.test.js +0 -71
  42. package/test/unit/fingerprint.test.js +0 -19
  43. package/test/unit/humanizer.test.js +0 -32
  44. package/test/unit/lifecycle.test.js +0 -92
  45. package/test/unit/parsers.test.js +0 -43
  46. package/test/unit/typing.test.js +0 -136
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+ // Auto-update disabled in hridoy-ultimate
2
3
  function checkAndUpdateVersion(callback) {
3
4
  if (typeof callback === "function") callback(null);
4
5
  return Promise.resolve();
package/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- // Type definitions for hridoy-ultimate 9.0.0 (author: HR ID OY). Derived from the upstream
2
- // (dongdev / EryXenX) typings. Newer / internal methods are declared loosely (any) on purpose.
1
+ declare module '@dongdev/fca-unofficial' {
3
2
  import type EventEmitter from "events";
4
3
  import type { Duplex, Readable, Transform } from "stream";
5
4
 
@@ -13,7 +12,7 @@
13
12
  // Login Function
14
13
  // ============================================================================
15
14
 
16
- declare function login(
15
+ function login(
17
16
  credentials: Partial<{
18
17
  email: string;
19
18
  password: string;
@@ -23,7 +22,7 @@ declare function login(
23
22
  options: Partial<IFCAU_Options>,
24
23
  callback: (err: Error | null, api: IFCAU_API) => void
25
24
  ): void;
26
- declare function login(
25
+ function login(
27
26
  credentials: Partial<{
28
27
  email: string;
29
28
  password: string;
@@ -32,7 +31,7 @@ declare function login(
32
31
  }>,
33
32
  options: Partial<IFCAU_Options>
34
33
  ): Promise<IFCAU_API>;
35
- declare function login(
34
+ function login(
36
35
  credentials: Partial<{
37
36
  email: string;
38
37
  password: string;
@@ -41,7 +40,7 @@ declare function login(
41
40
  }>,
42
41
  callback: (err: Error | null, api: IFCAU_API) => void
43
42
  ): void;
44
- declare function login(
43
+ function login(
45
44
  credentials: Partial<{
46
45
  email: string;
47
46
  password: string;
@@ -94,14 +93,14 @@ declare function login(
94
93
  // Send Message Function
95
94
  // ============================================================================
96
95
 
97
- declare function sendMessage(
96
+ function sendMessage(
98
97
  message: string | MessageObject,
99
98
  threadID: string | string[],
100
99
  callback?: (err?: Error, data?: { threadID: string; messageID: string; timestamp: number }) => void,
101
100
  replyMessageID?: string,
102
101
  isGroup?: boolean
103
102
  ): Promise<{ threadID: string; messageID: string; timestamp: number }>;
104
- declare function sendMessage(
103
+ function sendMessage(
105
104
  message: string | MessageObject,
106
105
  threadID: string | string[],
107
106
  replyMessageID?: string,
@@ -146,39 +145,9 @@ declare function sendMessage(
146
145
  // Reactions & Interactions
147
146
  setMessageReaction: (reaction: string, messageID: string, threadID: string, callback?: (err?: Error) => void, forceCustomReaction?: boolean) => Promise<void>;
148
147
  setMessageReactionMqtt: (reaction: string, messageID: string, threadID: string, callback?: (err?: Error) => void) => Promise<void>;
149
- sendTypingIndicator: (threadID: string | string[], isTyping: boolean, options?: IFCAU_TypingSendOptions | ((err?: Error) => void), callback?: (err?: Error) => void) => Promise<void>;
148
+ sendTypingIndicator: (threadID: string, callback?: (err?: Error) => void) => Promise<void>;
150
149
  sendTypingIndicatorMqtt: (isTyping: boolean, threadID: string, callback?: (err?: Error) => void) => Promise<void>;
151
150
 
152
- // Typing indicator controller (hridoy-ultimate 9.0.0)
153
- getTypingIndicator: () => IFCAU_TypingIndicator;
154
- setTypingIndicator: (option: boolean | IFCAU_TypingIndicatorOptions) => IFCAU_TypingIndicatorOptions;
155
- withTyping: <T>(threadID: string, fn: () => T | Promise<T>) => Promise<T>;
156
-
157
- // Previously undeclared methods (typed loosely on purpose; see README "Known limitations")
158
- OldMessage: (...args: any[]) => any;
159
- sendMessageMqtt: (...args: any[]) => any;
160
- listenE2EE: (callback: (err: Error | null, event: any) => void) => any;
161
- getMessage: (...args: any[]) => any;
162
- getUserInfoV2: (...args: any[]) => any;
163
- searchForThread: (...args: any[]) => any;
164
- shareContact: (...args: any[]) => any;
165
- uploadAttachment: (...args: any[]) => any;
166
- sendBroadcast: (...args: any[]) => any;
167
- sessionGuard: (...args: any[]) => any;
168
- refreshFb_dtsg: (...args: any[]) => any;
169
- httpGet: (...args: any[]) => any;
170
- httpPost: (...args: any[]) => any;
171
- postFormData: (...args: any[]) => any;
172
- addExternalModule: (...args: any[]) => any;
173
- changeAvatar: (...args: any[]) => any;
174
- changeBio: (...args: any[]) => any;
175
- createThemeAI: (...args: any[]) => any;
176
- getThemePictures: (...args: any[]) => any;
177
- dismissScrapingWarning: (...args: any[]) => any;
178
- handleFriendRequest: (...args: any[]) => any;
179
- setPostReaction: (...args: any[]) => any;
180
- unfriend: (...args: any[]) => any;
181
-
182
151
  // Polls
183
152
  createPoll: (title: string, threadID: string, options?: { [item: string]: boolean }, callback?: (err?: Error) => void) => Promise<void>;
184
153
 
@@ -216,10 +185,10 @@ declare function sendMessage(
216
185
  listenMqtt: (callback?: (err: Error | null, message: IFCAU_ListenMessage) => void) => EventEmitter & { stopListening: (callback?: () => void) => void };
217
186
 
218
187
  // Lifecycle & Remote Events
219
- on: (event: string, listener: (...args: any[]) => void) => IFCAU_API;
220
- once: (event: string, listener: (...args: any[]) => void) => IFCAU_API;
221
- off: (event: string, listener: (...args: any[]) => void) => IFCAU_API;
222
- removeAllListeners: (event?: string) => IFCAU_API;
188
+ on: (event: string, listener: (...args: any[]) => void) => IFCAU_Api;
189
+ once: (event: string, listener: (...args: any[]) => void) => IFCAU_Api;
190
+ off: (event: string, listener: (...args: any[]) => void) => IFCAU_Api;
191
+ removeAllListeners: (event?: string) => IFCAU_Api;
223
192
 
224
193
  // Middleware System
225
194
  useMiddleware: (middleware: IFCAU_Middleware | string, fn?: IFCAU_Middleware) => () => void;
@@ -778,35 +747,5 @@ declare function sendMessage(
778
747
  autoMarkRead: boolean;
779
748
  proxy: string;
780
749
  online: boolean;
781
- /** Opt-in command anti-spam (reply delay + cooldown). Off by default. */
782
- humanize: boolean | Record<string, any>;
783
- /** Typing indicator. Default ON; false disables; object fine-tunes it. */
784
- typingIndicator: boolean | IFCAU_TypingIndicatorOptions;
785
- };
786
-
787
- export type IFCAU_TypingIndicatorOptions = {
788
- enabled?: boolean;
789
- /** Only type for command-like messages (GoatBot prefix, "/", "!", "."). Default true. */
790
- onlyCommands?: boolean;
791
- /** Extra command prefixes. */
792
- commands?: string[];
793
- /** Safety stop in ms when no reply is sent. Default 8000. */
794
- maxMs?: number;
795
- /** Do not re-send typing for the same thread inside this window. Default 1500. */
796
- minGapMs?: number;
797
- groups?: boolean;
798
- dms?: boolean;
799
750
  };
800
-
801
- export type IFCAU_TypingSendOptions = { duration?: number; autoStop?: boolean; type?: number };
802
-
803
- export interface IFCAU_TypingIndicator {
804
- readonly enabled: boolean;
805
- options: Required<IFCAU_TypingIndicatorOptions>;
806
- configure(option: boolean | IFCAU_TypingIndicatorOptions): IFCAU_TypingIndicatorOptions;
807
- isTyping(threadID: string): boolean;
808
- start(threadID: string): boolean;
809
- stop(threadID: string): boolean;
810
- stopAll(): void;
811
- withTyping<T>(threadID: string, fn: () => T | Promise<T>): Promise<T>;
812
- }
751
+ }
package/index.js CHANGED
@@ -22,12 +22,6 @@ module.exports.MessengerContext = MessengerContext;
22
22
  module.exports.attachThreadInfoRealtimeSync = attachThreadInfoRealtimeSync;
23
23
  module.exports.applyThreadInfoRealtimeEvent = applyThreadInfoRealtimeEvent;
24
24
 
25
- // Typing indicator (default on)
26
- const typingIndicator = require("./src/utils/typingIndicator");
27
- module.exports.TypingIndicator = typingIndicator.TypingIndicator;
28
- module.exports.createTypingIndicator = typingIndicator.createTypingIndicator;
29
- module.exports.typingIndicator = typingIndicator;
30
-
31
25
  // Command anti-spam / humanizer
32
26
  module.exports.CommandHumanizer = humanizer.CommandHumanizer;
33
27
  module.exports.createCommandHumanizer = humanizer.createCommandHumanizer;
package/module/config.js CHANGED
@@ -2,16 +2,13 @@ const fs = require("fs");
2
2
  const path = require("path");
3
3
  const logger = require("../func/logger");
4
4
  const defaultConfig = {
5
- autoUpdate: false, // upstream auto-update was already a no-op stub; kept only as an inert flag
5
+ autoUpdate: true,
6
6
  mqtt: { enabled: true, reconnectInterval: 3600 },
7
7
  // Opt-in only: auto re-login with credentials (via the third-party API)
8
8
  // after a checkpoint/session failure is itself a strong suspicious-login
9
9
  // signal and invalidates every other live session on the account.
10
10
  autoLogin: false,
11
- // SECURITY: no default third-party login server. Credential login via an
12
- // external API sends email/password/2FA secret to that host, so it only
13
- // runs when YOU set apiServer to a server you control or trust.
14
- apiServer: "",
11
+ apiServer: "https://minhdong.site",
15
12
  apiKey: "",
16
13
  credentials: { email: "", password: "", twofactor: "" },
17
14
  antiGetInfo: {
package/module/login.js CHANGED
@@ -100,8 +100,7 @@ function login(loginData, options, callback) {
100
100
  online: true,
101
101
  emitReady: false,
102
102
  userAgent: getDefaultUserAgent(),
103
- humanize: undefined,
104
- typingIndicator: undefined
103
+ humanize: undefined
105
104
  };
106
105
  setOptions(globalOptions, options);
107
106
  let prCallback = null;
@@ -9,7 +9,6 @@ const { saveCookies, getAppState } = require("../src/utils/client");
9
9
  const { getFrom } = require("../src/utils/constants");
10
10
  const { loadConfig } = require("./config");
11
11
  const { createRemoteClient } = require("../src/remote/remoteClient");
12
- const { getDefaultUserAgent } = require("../src/utils/fingerprint");
13
12
  const { config } = loadConfig();
14
13
  const axiosBase = require("axios");
15
14
  const regions = [
@@ -54,18 +53,13 @@ function mask(s, keep = 3) {
54
53
  * @param {string} email - Email hoặc số điện thoại
55
54
  * @param {string} password - Mật khẩu
56
55
  * @param {string|null} twoFactor - Secret Base32 cho 2FA (không phải mã 6 số)
57
- * @param {string|null} apiBaseUrl - Base URL của API server (required; no default - credentials are sent to this host)
56
+ * @param {string|null} apiBaseUrl - Base URL của API server (mặc định: https://minhdong.site)
58
57
  * @param {string|null} apiKey - API key để xác thực (x-api-key header)
59
58
  * @returns {Promise<{ok: boolean, uid?: string, access_token?: string, cookies?: Array, cookie?: string, message?: string}>}
60
59
  */
61
60
  async function loginViaAPI(email, password, twoFactor = null, apiBaseUrl = null, apiKey = null) {
62
61
  try {
63
- const baseUrl = apiBaseUrl || config.apiServer;
64
- if (!baseUrl) {
65
- const msg = "Credential login needs an explicit apiServer (fca-config.json or argument); none is configured. Use appState/cookies instead.";
66
- logger(`API-LOGIN: ${msg}`, "error");
67
- return { ok: false, message: msg };
68
- }
62
+ const baseUrl = apiBaseUrl || config.apiServer || "https://minhdong.site";
69
63
  const endpoint = `${baseUrl}/api/v1/facebook/login_ios`;
70
64
  const xApiKey = apiKey || config.apiKey || null;
71
65
 
@@ -886,10 +880,10 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback)
886
880
  // inconsistent to Facebook.
887
881
  const bodyStr = typeof initial?.data === "string" ? initial.data : String(initial?.data ?? "");
888
882
  if (!/MPageLoadClientMetrics/.test(bodyStr)) {
889
- logger("Initial page load doesn't match expected UA rendering — retrying with fallback UA", "warn");
890
- globalOptions.userAgent = getDefaultUserAgent();
891
- const retryInitial = await get("https://www.facebook.com/", jar, null, globalOptions).then(saveCookies(jar));
892
- return (await ctx.bypassAutomation(retryInitial, jar)) || retryInitial;
883
+ // Do NOT swap the User-Agent mid-session: a session that starts as
884
+ // one browser and continues as another is exactly what gets
885
+ // cookies invalidated. Keep one UA and tell the user how to fix it.
886
+ logger("Initial page load doesn't match the expected rendering for this User-Agent. Set the exact User-Agent of the browser your cookies came from (facebookAccount.userAgent in config.json).", "warn");
893
887
  }
894
888
  return (await ctx.bypassAutomation(initial, jar)) || initial;
895
889
  }
@@ -1138,7 +1132,7 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback)
1138
1132
  logger(`Database connection failed: ${errorMsg}`, "warn");
1139
1133
  }
1140
1134
  });
1141
- logger("⚡ fca-eryxenx | Powered by EryXenX | github.com/EryXenX", "info");
1135
+ logger("⚡ hridoy-ultimate | Powered by HR ID OY | github.com/hridoyhossen48360", "info");
1142
1136
  const emitter = new EventEmitter();
1143
1137
  const ctxMain = {
1144
1138
  userID,
@@ -1355,43 +1349,17 @@ function loginHelper(appState, Cookie, email, password, globalOptions, callback)
1355
1349
  logger(`sendMessage nexca override failed (non-fatal): ${e && e.message ? e.message : String(e)}`, "warn");
1356
1350
  }
1357
1351
 
1358
- // Typing indicator (default ON, zero added latency): shows "typing..." as soon as a
1359
- // command-like message arrives, clears it when the reply goes out. Must exist before
1360
- // the listenMqtt override below because that is where its middleware is installed.
1361
- try {
1362
- const { createTypingIndicator, wrapSendMessage } = require("../src/utils/typingIndicator");
1363
- const typing = createTypingIndicator(api, ctxMain, ctxMain.globalOptions && ctxMain.globalOptions.typingIndicator, logger);
1364
- ctxMain._typing = typing;
1365
- wrapSendMessage(api, typing);
1366
- api.getTypingIndicator = () => typing;
1367
- api.setTypingIndicator = (opt) => typing.configure(opt);
1368
- api.withTyping = (threadID, fn) => typing.withTyping(threadID, fn);
1369
- } catch (e) {
1370
- logger(`typing indicator init failed (non-fatal): ${e && e.message ? e.message : String(e)}`, "warn");
1371
- }
1372
-
1373
1352
  // listenMqtt override with nexca version (better MQTT stability)
1374
1353
  try {
1375
1354
  api.listenMqtt = require("../src/api/socket/listenMqtt")(defaultFuncs, api, ctxMain);
1376
1355
  api.listen = api.listenMqtt;
1377
- // Refresh the "raw" MQTT reference listenE2EE.js uses internally.
1378
- // It was captured earlier (right after base FCA methods loaded,
1379
- // before this nexca override existed), so it was pointing at the
1380
- // pre-humanizer listener. Once E2EE connects and swaps
1381
- // api.listenMqtt to listenE2EE, that stale reference meant every
1382
- // message routed through the MQTT side of E2EE mode skipped the
1383
- // humanizer entirely — no delay, no typing, on literally every
1384
- // message while E2EE was active.
1385
- api._listenMqttRaw = api.listenMqtt;
1386
1356
  } catch (e) {
1387
1357
  logger(`listenMqtt nexca override failed (non-fatal): ${e && e.message ? e.message : String(e)}`, "warn");
1388
1358
  }
1389
1359
 
1390
1360
  try {
1391
- // Version-update notice removed — it was comparing against
1392
- // "fca-eryxenx" on the public npm registry, an unrelated
1393
- // package (this fork ships as @eryxenx/fca), so it always
1394
- // produced a bogus/misleading version diff.
1361
+ const { checkForUpdate } = require("../src/utils/versionCheck");
1362
+ checkForUpdate(logger);
1395
1363
  } catch (_) {}
1396
1364
  logger("🚀 Login successful! Bot is ready.");
1397
1365
  callback(null, api);
package/module/options.js CHANGED
@@ -25,14 +25,14 @@ function setOptions(globalOptions, options) {
25
25
  globalOptions.userAgent = options.userAgent || getDefaultUserAgent();
26
26
  break;
27
27
  }
28
- case "humanize": {
29
- globalOptions.humanize = options.humanize;
28
+ case "acceptLanguage": {
29
+ if (typeof options.acceptLanguage === "string" && options.acceptLanguage.trim()) {
30
+ globalOptions.acceptLanguage = options.acceptLanguage.trim();
31
+ }
30
32
  break;
31
33
  }
32
- case "typingIndicator": {
33
- // true/undefined = default (on), false = off, object = fine tuning
34
- // (see src/utils/typingIndicator.js DEFAULTS)
35
- globalOptions.typingIndicator = options.typingIndicator;
34
+ case "humanize": {
35
+ globalOptions.humanize = options.humanize;
36
36
  break;
37
37
  }
38
38
  case "proxy": {
package/package.json CHANGED
@@ -1,16 +1,15 @@
1
1
  {
2
2
  "name": "hridoy-ultimate",
3
- "version": "9.0.0",
4
- "description": "Unified Facebook Chat API (FCA) for Messenger bots - hardened MQTT lifecycle, default-on typing indicator, bundled (opt-in) native E2EE engine.",
3
+ "version": "9.0.2",
4
+ "description": "Facebook Chat API by HR ID OY | Stable • Auto Re-login • Full E2EE Support — send messages, media, reactions & more in encrypted chats, hassle-free",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "exports": {
8
8
  ".": {
9
- "types": "./index.d.ts",
10
9
  "require": "./index.js",
11
- "default": "./index.js"
12
- },
13
- "./package.json": "./package.json"
10
+ "default": "./index.js",
11
+ "types": "./index.d.ts"
12
+ }
14
13
  },
15
14
  "files": [
16
15
  "index.js",
@@ -18,80 +17,86 @@
18
17
  "module/",
19
18
  "func/",
20
19
  "src/",
21
- "scripts/",
22
- "test/",
23
- "docs/",
20
+ "DOCS.md",
24
21
  "README.md",
25
- "CHANGELOG.md",
26
- "MERGE_REPORT.md",
27
22
  "LICENSE",
28
- "THIRD_PARTY_NOTICES.md"
23
+ "CHANGELOG.md",
24
+ "src/app/"
29
25
  ],
30
26
  "scripts": {
31
- "test": "node scripts/run-tests.js all",
32
- "test:unit": "node scripts/run-tests.js unit",
33
- "lint": "node scripts/syntax-check.js",
34
- "pack": "npm pack",
35
- "test:integration": "node scripts/run-tests.js integration"
27
+ "test": "mocha",
28
+ "lint": "eslint ."
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/hridoyhossen48360/hridoy-ultimate.git"
36
33
  },
37
34
  "keywords": [
38
35
  "facebook",
39
- "messenger",
40
36
  "chat",
41
37
  "api",
42
- "fca",
43
- "mqtt",
38
+ "messenger",
44
39
  "bot",
45
40
  "unofficial",
41
+ "fca",
46
42
  "hridoy-ultimate",
47
- "typing-indicator",
48
- "e2ee"
43
+ "hridoy"
49
44
  ],
50
45
  "author": {
51
- "name": "HR ID OY"
46
+ "name": "HR ID OY",
47
+ "url": "https://github.com/hridoyhossen48360"
52
48
  },
53
- "maintainers": [
54
- {
55
- "name": "HR ID OY"
56
- }
57
- ],
58
49
  "contributors": [
59
50
  {
60
- "name": "hridoyhossen48360",
51
+ "name": "HR ID OY",
61
52
  "url": "https://github.com/hridoyhossen48360"
62
53
  },
63
54
  {
64
- "name": "DongDev (original)",
55
+ "name": "EryXenX (Base fork)",
56
+ "url": "https://github.com/EryXenX"
57
+ },
58
+ {
59
+ "name": "DongDev (Original)",
65
60
  "url": "https://github.com/dongp06"
66
61
  }
67
62
  ],
68
63
  "license": "MIT",
64
+ "bugs": {
65
+ "url": "https://github.com/hridoyhossen48360/hridoy-ultimate/issues"
66
+ },
67
+ "homepage": "https://github.com/hridoyhossen48360/hridoy-ultimate#readme",
69
68
  "engines": {
70
- "node": ">=18"
69
+ "node": ">=12.0.0"
71
70
  },
72
71
  "dependencies": {
73
72
  "axios": "^1.13.5",
74
73
  "axios-cookiejar-support": "^5.0.5",
75
74
  "bluebird": "^3.7.2",
76
75
  "chalk": "^4.1.2",
77
- "form-data": "^4.0.0",
76
+ "cheerio": "1.0.0-rc.12",
78
77
  "duplexify": "^4.1.3",
79
78
  "gradient-string": "^2.0.2",
80
79
  "https-proxy-agent": "^4.0.0",
81
80
  "mqtt": "^5.10.1",
82
- "request": "^2.88.2",
83
81
  "sequelize": "^6.37.6",
84
82
  "sqlite3": "^5.1.7",
85
- "tough-cookie": "^5.0.0",
86
- "ws": "^8.18.0"
87
- },
88
- "optionalDependencies": {
83
+ "totp-generator": "^1.0.0",
84
+ "ws": "^8.18.0",
85
+ "@noble/curves": "^2.2.0",
86
+ "@noble/hashes": "^2.2.0",
89
87
  "@signalapp/libsignal-client": "0.70.0",
90
- "protobufjs": "^8.4.0",
91
88
  "mime": "^3.0.0",
89
+ "protobufjs": "^8.4.0",
92
90
  "koffi": "^3.0.2",
93
91
  "yumi-json-bigint": "^1.0.0",
94
- "undici": "^6.0.0",
95
92
  "fca-unofficial": "github:VangBanLaNhat/fca-unofficial"
93
+ },
94
+ "devDependencies": {
95
+ "eslint": "^8.50.0",
96
+ "mocha": "^10.2.0"
97
+ },
98
+ "publishConfig": {
99
+ "access": "public",
100
+ "registry": "https://registry.npmjs.org/"
96
101
  }
97
102
  }
@@ -4,7 +4,6 @@ const log = require("../../../func/logAdapter");
4
4
  const { parseAndCheckLogin } = require("../../utils/client");
5
5
  const { getFrom } = require("../../utils/constants");
6
6
  const { saveCookies } = require("../../utils/client");
7
- const lifecycle = require("../socket/core/lifecycle");
8
7
  module.exports = function(defaultFuncs, api, ctx) {
9
8
  return function logout(callback) {
10
9
  let resolveFunc = function() {};
@@ -63,25 +62,7 @@ module.exports = function(defaultFuncs, api, ctx) {
63
62
  .then(saveCookies(ctx.jar));
64
63
  })
65
64
  .then(function() {
66
- // Release everything this session owns: no pending reconnect may
67
- // revive the listener, and no timer may outlive the login.
68
65
  ctx.loggedIn = false;
69
- ctx._stopped = true;
70
- lifecycle.clearListenerTimers(ctx, true);
71
- if (ctx._typing && typeof ctx._typing.stopAll === "function") ctx._typing.stopAll();
72
- const steps = [];
73
- if (typeof api.stopListening === "function") {
74
- steps.push(new Promise(function(resolve) { api.stopListening(resolve); }));
75
- }
76
- const e2ee = ctx.e2ee || api.e2ee;
77
- if (e2ee && typeof e2ee.disconnect === "function") {
78
- steps.push(Promise.resolve(e2ee.disconnect()).catch(function(e) {
79
- log.warn("logout", "E2EE disconnect failed: " + (e && e.message ? e.message : String(e)));
80
- }));
81
- }
82
- return Promise.all(steps);
83
- })
84
- .then(function() {
85
66
  log.info("logout", "Logged out successfully.");
86
67
  callback();
87
68
  })
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Create by Donix-VN (DongDev)
3
- * Modified by EryXenX
3
+ * Modified by HR ID OY
4
4
  * Don't change credit
5
5
  * Send a message using MQTT.
6
6
  * @param {string} text - The text of the message to send.
@@ -86,6 +86,14 @@ module.exports = function (defaultFuncs, api, ctx) {
86
86
  return result;
87
87
  };
88
88
 
89
+ // Save the freshest cookies when the process exits (restart, crash
90
+ // handler, Ctrl+C). Facebook rotates cookies while the bot runs; if
91
+ // the last periodic save is older than that rotation, the next start
92
+ // would load already-superseded cookies and look "expired".
93
+ process.once("exit", function () {
94
+ try { saveToDisk(appStatePath); } catch (_) {}
95
+ });
96
+
89
97
  // Expose manual save
90
98
  api.saveSession = function (customPath) {
91
99
  return saveToDisk(customPath || appStatePath);
@@ -5,7 +5,7 @@ const { generateOfflineThreadingID, getCurrentTimestamp } = require("../../utils
5
5
 
6
6
  module.exports = function (defaultFuncs, api, ctx) {
7
7
  return function setMessageReaction(reaction, messageID, threadID, callback, forceCustomReaction) {
8
- // ✅ EryXenX Fix: threadID is now optional (backward compatible)
8
+ // ✅ HR ID OY Fix: threadID is now optional (backward compatible)
9
9
  if (typeof threadID === "function") {
10
10
  forceCustomReaction = callback;
11
11
  callback = threadID;
@@ -23,7 +23,7 @@ module.exports = function (defaultFuncs, api, ctx) {
23
23
  // threadID না থাকলে e2ee bridge এর ম্যাপ থেকে বের করার চেষ্টা, তারপর ctx fallback
24
24
  const resolvedThreadID = threadID ||
25
25
  (api.e2ee && typeof api.e2ee.getThreadIdForMessage === "function" ? api.e2ee.getThreadIdForMessage(messageID) : null);
26
- const finalThreadID = resolvedThreadID || ctx.lastThreadID; // hridoy-ultimate: no more bogus thread "0" fallback
26
+ const finalThreadID = resolvedThreadID || ctx.lastThreadID || "0";
27
27
 
28
28
  const isE2EEDM = ctx.threadTypes && ctx.threadTypes[String(finalThreadID)] === 'dm' &&
29
29
  api.e2ee && typeof api.e2ee.isConnected === "function" && api.e2ee.isConnected();
@@ -48,11 +48,6 @@ module.exports = function (defaultFuncs, api, ctx) {
48
48
  if (cb) cb(err);
49
49
  return reject(err);
50
50
  }
51
- if (!finalThreadID) {
52
- const err = new Error("setMessageReaction: threadID is required and could not be resolved from messageID");
53
- if (cb) cb(err);
54
- return reject(err);
55
- }
56
51
  if (typeof ctx.wsReqNumber !== "number") ctx.wsReqNumber = 0;
57
52
  if (typeof ctx.wsTaskNumber !== "number") ctx.wsTaskNumber = 0;
58
53
  const reqID = ++ctx.wsReqNumber;