@dongdev/fca-unofficial 3.0.29 → 3.0.30

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 (61) hide show
  1. package/CHANGELOG.md +229 -132
  2. package/DOCS.md +82 -3
  3. package/README.md +524 -632
  4. package/func/logAdapter.js +33 -0
  5. package/index.d.ts +6 -0
  6. package/module/config.js +11 -1
  7. package/module/loginHelper.js +63 -4
  8. package/package.json +88 -81
  9. package/src/api/action/changeAvatar.js +1 -1
  10. package/src/api/action/changeBio.js +1 -1
  11. package/src/api/action/handleFriendRequest.js +1 -1
  12. package/src/api/action/logout.js +1 -1
  13. package/src/api/action/refreshFb_dtsg.js +1 -1
  14. package/src/api/action/setPostReaction.js +1 -1
  15. package/src/api/action/unfriend.js +1 -1
  16. package/src/api/http/postFormData.js +1 -1
  17. package/src/api/messaging/changeArchivedStatus.js +1 -1
  18. package/src/api/messaging/changeBlockedStatus.js +1 -1
  19. package/src/api/messaging/changeGroupImage.js +1 -1
  20. package/src/api/messaging/changeNickname.js +1 -1
  21. package/src/api/messaging/changeThreadEmoji.js +1 -1
  22. package/src/api/messaging/createNewGroup.js +1 -1
  23. package/src/api/messaging/createThemeAI.js +1 -1
  24. package/src/api/messaging/deleteMessage.js +1 -1
  25. package/src/api/messaging/deleteThread.js +1 -1
  26. package/src/api/messaging/getFriendsList.js +1 -1
  27. package/src/api/messaging/getMessage.js +1 -1
  28. package/src/api/messaging/getThemePictures.js +1 -1
  29. package/src/api/messaging/handleMessageRequest.js +1 -1
  30. package/src/api/messaging/markAsDelivered.js +1 -1
  31. package/src/api/messaging/markAsRead.js +1 -1
  32. package/src/api/messaging/markAsReadAll.js +1 -1
  33. package/src/api/messaging/markAsSeen.js +1 -1
  34. package/src/api/messaging/muteThread.js +1 -1
  35. package/src/api/messaging/resolvePhotoUrl.js +1 -1
  36. package/src/api/messaging/sendMessage.js +1 -1
  37. package/src/api/messaging/setTitle.js +1 -1
  38. package/src/api/messaging/unsendMessage.js +1 -1
  39. package/src/api/messaging/uploadAttachment.js +1 -1
  40. package/src/api/socket/core/connectMqtt.js +16 -8
  41. package/src/api/socket/core/emitAuth.js +4 -0
  42. package/src/api/socket/core/getSeqID.js +6 -8
  43. package/src/api/socket/core/getTaskResponseData.js +3 -0
  44. package/src/api/socket/core/parseDelta.js +9 -0
  45. package/src/api/socket/detail/buildStream.js +11 -4
  46. package/src/api/socket/detail/constants.js +4 -0
  47. package/src/api/socket/listenMqtt.js +11 -5
  48. package/src/api/threads/getThreadHistory.js +1 -1
  49. package/src/api/threads/getThreadInfo.js +245 -388
  50. package/src/api/threads/getThreadList.js +1 -1
  51. package/src/api/threads/getThreadPictures.js +1 -1
  52. package/src/api/users/getUserID.js +1 -1
  53. package/src/api/users/getUserInfo.js +80 -8
  54. package/src/database/models/thread.js +5 -0
  55. package/src/remote/remoteClient.js +123 -0
  56. package/src/utils/broadcast.js +51 -0
  57. package/src/utils/loginParser.js +19 -1
  58. package/src/utils/request.js +33 -6
  59. package/.gitattributes +0 -2
  60. package/Fca_Database/database.sqlite +0 -0
  61. package/LICENSE-MIT +0 -21
@@ -8,7 +8,7 @@ const fs = require("fs");
8
8
  const path = require("path");
9
9
  const stream = require("stream");
10
10
  const { URL } = require("url");
11
- const log = require("npmlog");
11
+ const log = require("../../../func/logAdapter");
12
12
 
13
13
  let http = null;
14
14
  let cookieJar = new CookieJar();
@@ -1,5 +1,13 @@
1
1
  "use strict";
2
+ /**
3
+ * MQTT/WebSocket listener for Facebook Messenger real-time events.
4
+ * Connects to edge-chat.facebook.com, subscribes to topics, parses deltas and typing/presence.
5
+ */
2
6
  const { formatID } = require("../../../utils/format");
7
+
8
+ const DEFAULT_RECONNECT_DELAY_MS = 2000;
9
+ const T_MS_WAIT_TIMEOUT_MS = 5000;
10
+
3
11
  module.exports = function createListenMqtt(deps) {
4
12
  const { WebSocket, mqtt, HttpsProxyAgent, buildStream, buildProxy,
5
13
  topics, parseDelta, getTaskResponseData, logger, emitAuth
@@ -8,7 +16,7 @@ module.exports = function createListenMqtt(deps) {
8
16
  return function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
9
17
 
10
18
  function scheduleReconnect(delayMs) {
11
- const d = (ctx._mqttOpt && ctx._mqttOpt.reconnectDelayMs) || 2000;
19
+ const d = (ctx._mqttOpt && ctx._mqttOpt.reconnectDelayMs) || DEFAULT_RECONNECT_DELAY_MS;
12
20
  const ms = typeof delayMs === "number" ? delayMs : d;
13
21
  if (ctx._reconnectTimer) {
14
22
  logger("mqtt reconnect already scheduled", "warn");
@@ -113,9 +121,8 @@ module.exports = function createListenMqtt(deps) {
113
121
  if (ctx._ending || ctx._cycling) return;
114
122
 
115
123
  if (ctx.globalOptions.autoReconnect && !ctx._ending) {
116
- const d = (ctx._mqttOpt && ctx._mqttOpt.reconnectDelayMs) || 2000;
124
+ const d = (ctx._mqttOpt && ctx._mqttOpt.reconnectDelayMs) || DEFAULT_RECONNECT_DELAY_MS;
117
125
  logger(`mqtt autoReconnect listenMqtt() in ${d}ms`, "warn");
118
- // Use scheduleReconnect to prevent multiple reconnections
119
126
  scheduleReconnect(d);
120
127
  } else {
121
128
  globalCallback({ type: "stop_listen", error: msg || "Connection refused" }, null);
@@ -124,7 +131,7 @@ module.exports = function createListenMqtt(deps) {
124
131
 
125
132
  mqttClient.on("connect", function () {
126
133
  if (process.env.OnStatus === undefined) {
127
- logger("fca-unoffcial premium", "info");
134
+ logger("fca-unofficial", "info");
128
135
  process.env.OnStatus = true;
129
136
  }
130
137
  ctx._cycling = false;
@@ -141,7 +148,7 @@ module.exports = function createListenMqtt(deps) {
141
148
  mqttClient.publish(topic, JSON.stringify(queue), { qos: 1, retain: false });
142
149
  mqttClient.publish("/foreground_state", JSON.stringify({ foreground: chatOn }), { qos: 1 });
143
150
  mqttClient.publish("/set_client_settings", JSON.stringify({ make_user_available_when_in_foreground: true }), { qos: 1 });
144
- const d = (ctx._mqttOpt && ctx._mqttOpt.reconnectDelayMs) || 2000;
151
+ const d = (ctx._mqttOpt && ctx._mqttOpt.reconnectDelayMs) || DEFAULT_RECONNECT_DELAY_MS;
145
152
  let rTimeout = setTimeout(function () {
146
153
  rTimeout = null;
147
154
  if (ctx._ending) {
@@ -155,7 +162,7 @@ module.exports = function createListenMqtt(deps) {
155
162
  }
156
163
  } catch (_) { }
157
164
  scheduleReconnect(d);
158
- }, 5000);
165
+ }, T_MS_WAIT_TIMEOUT_MS);
159
166
 
160
167
  // Store timeout reference for cleanup
161
168
  ctx._rTimeout = rTimeout;
@@ -216,8 +223,9 @@ module.exports = function createListenMqtt(deps) {
216
223
  } else if (topic === "/ls_resp") {
217
224
  const parsedPayload = JSON.parse(jsonMessage.payload);
218
225
  const reqID = jsonMessage.request_id;
219
- if (ctx["tasks"].has(reqID)) {
220
- const taskData = ctx["tasks"].get(reqID);
226
+ const tasks = ctx.tasks;
227
+ if (tasks && tasks instanceof Map && tasks.has(reqID)) {
228
+ const taskData = tasks.get(reqID);
221
229
  const { type: taskType, callback: taskCallback } = taskData;
222
230
  const taskRespData = getTaskResponseData(taskType, parsedPayload);
223
231
  if (taskRespData == null) taskCallback("error", null);
@@ -1,4 +1,8 @@
1
1
  "use strict";
2
+ /**
3
+ * Emits account_inactive to the global callback and cleans up MQTT/timers/scheduler.
4
+ * Used when login is invalid, blocked, or session is lost.
5
+ */
2
6
  module.exports = function createEmitAuth({ logger }) {
3
7
  return function emitAuth(ctx, api, globalCallback, reason, detail) {
4
8
  // Clean up all timers
@@ -1,9 +1,13 @@
1
1
  "use strict";
2
+ /**
3
+ * Fetches MQTT sync sequence ID from GraphQL and starts listenMqtt.
4
+ * Handles retries and auto re-login via fca-config.json when session expires.
5
+ */
2
6
  const { getType } = require("../../../utils/format");
3
7
  const { parseAndCheckLogin, saveCookies } = require("../../../utils/client");
4
8
  const path = require("path");
9
+ const loginHelper = require("../../../../module/loginHelper");
5
10
 
6
- // Load config for auto-login credentials
7
11
  function getConfig() {
8
12
  try {
9
13
  const configPath = path.join(process.cwd(), "fca-config.json");
@@ -51,7 +55,6 @@ async function tryAutoLogin(logger, config, ctx, defaultFuncs) {
51
55
  logger("getSeqID: attempting auto re-login via API...", "warn");
52
56
 
53
57
  try {
54
- const loginHelper = require("../../../../module/loginHelper");
55
58
  const result = await loginHelper.tokensViaAPI(
56
59
  email,
57
60
  password,
@@ -60,14 +63,9 @@ async function tryAutoLogin(logger, config, ctx, defaultFuncs) {
60
63
  );
61
64
 
62
65
  if (result && result.status) {
63
- // Handle cookies - can be array, cookie string header, or both
64
- // Import normalizeCookieHeaderString from loginHelper
65
- const loginHelper = require("../../../../module/loginHelper");
66
66
  const normalizeCookieHeaderString = loginHelper.normalizeCookieHeaderString;
67
-
68
67
  let cookiePairs = [];
69
-
70
- // If cookies is a string (cookie header format), parse it
68
+
71
69
  if (typeof result.cookies === "string") {
72
70
  cookiePairs = normalizeCookieHeaderString(result.cookies);
73
71
  }
@@ -1,4 +1,7 @@
1
1
  "use strict";
2
+ /**
3
+ * Maps /ls_resp task types to a normalized response shape for send_message_mqtt, set_message_reaction, edit_message.
4
+ */
2
5
  module.exports = function getTaskResponseData(taskType, payload) {
3
6
  try {
4
7
  switch (taskType) {
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
+ /**
3
+ * Parses MQTT delta payloads into normalized events: NewMessage, ClientPayload (reactions, unsend, reply), read receipts, etc.
4
+ */
2
5
  const { formatDeltaEvent, formatMessage, _formatAttachment, formatDeltaMessage, formatDeltaReadReceipt, formatID, getType, decodeClientPayload, getMentionsFromDeltaMessage } = require("../../../utils/format");
3
6
  const logger = require("../../../../func/logger");
7
+
4
8
  module.exports = function createParseDelta(deps) {
5
9
  const { parseAndCheckLogin } = deps;
6
10
  return function parseDelta(defaultFuncs, api, ctx, globalCallback, { delta }) {
@@ -15,6 +19,11 @@ module.exports = function createParseDelta(deps) {
15
19
  }
16
20
  if (fmtMsg) {
17
21
  if (!ctx.globalOptions.selfListen && fmtMsg.senderID === ctx.userID) return;
22
+ if (typeof ctx._updateThreadFromMessage === "function") {
23
+ try {
24
+ ctx._updateThreadFromMessage(fmtMsg);
25
+ } catch { }
26
+ }
18
27
  globalCallback(null, fmtMsg);
19
28
  }
20
29
  } else {
@@ -1,8 +1,15 @@
1
1
  "use strict";
2
-
2
+ /**
3
+ * Builds a duplex stream over WebSocket for MQTT: proxy for writes, PassThrough for reads.
4
+ * Handles ping/pong, liveness timeout, and clean shutdown.
5
+ */
3
6
  const { Writable, PassThrough } = require("stream");
4
7
  const Duplexify = require("duplexify");
5
8
 
9
+ const PING_INTERVAL_MS = 30000;
10
+ const LIVENESS_CHECK_MS = 10000;
11
+ const LIVENESS_MAX_IDLE_MS = 65000;
12
+
6
13
  function buildProxy() {
7
14
  let target = null;
8
15
  let ended = false;
@@ -94,13 +101,13 @@ function buildStream(options, WebSocket, Proxy) {
94
101
  } else {
95
102
  try { ws.send("ping"); } catch { }
96
103
  }
97
- }, 30000);
104
+ }, PING_INTERVAL_MS);
98
105
  livenessTimer = setInterval(() => {
99
106
  if (!ws || ws.readyState !== 1) return;
100
- if (Date.now() - lastActivity > 65000) {
107
+ if (Date.now() - lastActivity > LIVENESS_MAX_IDLE_MS) {
101
108
  try { typeof ws.terminate === "function" ? ws.terminate() : ws.close(); } catch { }
102
109
  }
103
- }, 10000);
110
+ }, LIVENESS_CHECK_MS);
104
111
  };
105
112
 
106
113
  const onMessage = data => {
@@ -1,4 +1,8 @@
1
1
  "use strict";
2
+ /**
3
+ * MQTT topic list for Facebook Messenger real-time connection.
4
+ * Subscriptions are created in connectMqtt on "connect".
5
+ */
2
6
  module.exports = {
3
7
  topics: [
4
8
  "/ls_req",
@@ -1,4 +1,8 @@
1
1
  "use strict";
2
+ /**
3
+ * Socket/MQTT entry: wires getSeqID -> listenMqtt, middleware, stopListening, and post guard.
4
+ * Exported as the function that attaches listenMqtt + middleware API to the login context.
5
+ */
2
6
  const mqtt = require("mqtt");
3
7
  const WebSocket = require("ws");
4
8
  const HttpsProxyAgent = require("https-proxy-agent");
@@ -13,15 +17,17 @@ const createGetSeqID = require("./core/getSeqID");
13
17
  const getTaskResponseData = require("./core/getTaskResponseData");
14
18
  const createEmitAuth = require("./core/emitAuth");
15
19
  const createMiddlewareSystem = require("./middleware");
20
+
21
+ const CYCLE_MS_DEFAULT = 60 * 60 * 1000;
22
+ const RECONNECT_DELAY_MS_DEFAULT = 2000;
23
+ const UNSUB_ALL_TIMEOUT_MS = 5000;
24
+
16
25
  const parseDelta = createParseDelta({ parseAndCheckLogin });
17
- // Create emitAuth first so it can be injected into both factories
18
26
  const emitAuth = createEmitAuth({ logger });
19
- // Pass emitAuth into connectMqtt so errors there can signal auth state
20
27
  const listenMqtt = createListenMqtt({ WebSocket, mqtt, HttpsProxyAgent, buildStream, buildProxy, topics, parseDelta, getTaskResponseData, logger, emitAuth });
21
- // Inject emitAuth into getSeqID so its catch handler can notify properly
22
28
  const getSeqIDFactory = createGetSeqID({ parseAndCheckLogin, listenMqtt, logger, emitAuth });
23
29
 
24
- const MQTT_DEFAULTS = { cycleMs: 60 * 60 * 1000, reconnectDelayMs: 2000, autoReconnect: true, reconnectAfterStop: false };
30
+ const MQTT_DEFAULTS = { cycleMs: CYCLE_MS_DEFAULT, reconnectDelayMs: RECONNECT_DELAY_MS_DEFAULT, autoReconnect: true, reconnectAfterStop: false };
25
31
  function mqttConf(ctx, overrides) {
26
32
  ctx._mqttOpt = Object.assign({}, MQTT_DEFAULTS, ctx._mqttOpt || {}, overrides || {});
27
33
  if (typeof ctx._mqttOpt.autoReconnect === "boolean") ctx.globalOptions.autoReconnect = ctx._mqttOpt.autoReconnect;
@@ -126,7 +132,7 @@ module.exports = function (defaultFuncs, api, ctx, opts) {
126
132
  logger("unsubAll timeout, proceeding anyway", "warn");
127
133
  if (cb) cb();
128
134
  }
129
- }, 5000); // 5 second timeout
135
+ }, UNSUB_ALL_TIMEOUT_MS);
130
136
 
131
137
  topics.forEach(t => {
132
138
  try {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- const log = require("npmlog");
3
+ const log = require("../../../func/logAdapter");
4
4
  const { parseAndCheckLogin } = require("../../utils/client");
5
5
  const { getAdminTextMessageType } = require("../../utils/format");
6
6
  function getExtension(original_extension, filename = "") {