@lazyneoaz/metachat 1.0.11 → 1.1.0
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/package.json +1 -1
- package/src/apis/changeAdminStatus.js +39 -50
- package/src/apis/changeArchivedStatus.js +16 -8
- package/src/apis/changeAvatar.js +2 -2
- package/src/apis/changeBio.js +1 -1
- package/src/apis/changeBlockedStatus.js +1 -1
- package/src/apis/changeGroupImage.js +22 -14
- package/src/apis/changeThreadEmoji.js +14 -8
- package/src/apis/createNewGroup.js +1 -1
- package/src/apis/createPoll.js +9 -3
- package/src/apis/deleteMessage.js +11 -8
- package/src/apis/deleteThread.js +1 -1
- package/src/apis/follow.js +27 -31
- package/src/apis/forwardMessage.js +1 -1
- package/src/apis/gcname.js +1 -1
- package/src/apis/getFriendsList.js +2 -2
- package/src/apis/getThreadInfo.js +1 -1
- package/src/apis/getThreadPictures.js +1 -1
- package/src/apis/handleMessageRequest.js +1 -1
- package/src/apis/listenMqtt.js +88 -3
- package/src/apis/markAsRead.js +15 -9
- package/src/apis/muteThread.js +1 -1
- package/src/apis/nickname.js +1 -1
- package/src/apis/pinMessage.js +110 -130
- package/src/apis/removeUserFromGroup.js +2 -2
- package/src/apis/resolvePhotoUrl.js +1 -1
- package/src/apis/searchForThread.js +1 -1
- package/src/apis/sendMessage.js +7 -0
- package/src/apis/setMessageReaction.js +3 -3
- package/src/apis/setMessageReactionMqtt.js +2 -2
- package/src/apis/setThreadThemeMqtt.js +70 -77
- package/src/apis/unfriend.js +1 -1
- package/src/apis/unsendMessage.js +71 -9
- package/src/app/state.js +1 -1
- package/src/types/index.d.ts +40 -1
- package/src/utils/antiSuspension.js +4 -4
- package/src/utils/auth-helpers.js +1 -1
- package/src/utils/lsRequest.js +2 -3
- package/src/utils/tokenRefresh.js +10 -1
package/src/apis/listenMqtt.js
CHANGED
|
@@ -499,6 +499,9 @@ async function listenMqtt(defaultFuncs, api, ctx, globalCallback, scheduleReconn
|
|
|
499
499
|
}
|
|
500
500
|
// Save connected state BEFORE clearing it — used for quick-close detection.
|
|
501
501
|
const wasConnected = ctx._mqttConnected;
|
|
502
|
+
try {
|
|
503
|
+
if (ctx._emitter) ctx._emitter.emit('disconnected', { timestamp: Date.now(), wasConnected });
|
|
504
|
+
} catch (_) {}
|
|
502
505
|
ctx._mqttConnected = false;
|
|
503
506
|
if (ctx._ending || ctx._cycling) return;
|
|
504
507
|
|
|
@@ -564,6 +567,15 @@ async function listenMqtt(defaultFuncs, api, ctx, globalCallback, scheduleReconn
|
|
|
564
567
|
ctx._mqttWatchdog = null;
|
|
565
568
|
}
|
|
566
569
|
ctx._mqttConnected = false;
|
|
570
|
+
|
|
571
|
+
if (!ctx._ending && !ctx._cycling && ctx.globalOptions.autoReconnect) {
|
|
572
|
+
try { mqttClient.end(true); } catch (_) {}
|
|
573
|
+
ctx._reconnectAttempts = (ctx._reconnectAttempts || 0) + 1;
|
|
574
|
+
const baseDelay = (ctx._mqttOpt && ctx._mqttOpt.reconnectDelayMs) || 2000;
|
|
575
|
+
const d = computeBackoffDelay(ctx, baseDelay, MQTT_MAX_BACKOFF, MQTT_JITTER_MAX);
|
|
576
|
+
utils.warn("MQTT", `Disconnect received — reconnecting in ${d}ms (attempt ${ctx._reconnectAttempts})`);
|
|
577
|
+
scheduleReconnect(d);
|
|
578
|
+
}
|
|
567
579
|
}));
|
|
568
580
|
|
|
569
581
|
mqttClient.on('offline', guard("offline", () => {
|
|
@@ -769,6 +781,22 @@ module.exports = (defaultFuncs, api, ctx, opts) => {
|
|
|
769
781
|
if (ctx._ending) return;
|
|
770
782
|
if (ctx._reconnectTimer) return;
|
|
771
783
|
utils.warn("MQTT", `Will reconnect in ${ms}ms`);
|
|
784
|
+
|
|
785
|
+
if (!ctx._reconnectStats) ctx._reconnectStats = { totalAttempts: 0, lastAttemptAt: null, nextAttemptAt: null, lastSuccessAt: null };
|
|
786
|
+
ctx._reconnectStats.totalAttempts = (ctx._reconnectStats.totalAttempts || 0) + 1;
|
|
787
|
+
ctx._reconnectStats.lastAttemptAt = Date.now();
|
|
788
|
+
ctx._reconnectStats.nextAttemptAt = Date.now() + ms;
|
|
789
|
+
try {
|
|
790
|
+
if (ctx._emitter) {
|
|
791
|
+
ctx._emitter.emit('reconnecting', {
|
|
792
|
+
attempt: ctx._reconnectAttempts || 0,
|
|
793
|
+
delayMs: ms,
|
|
794
|
+
nextAttemptAt: ctx._reconnectStats.nextAttemptAt,
|
|
795
|
+
timestamp: Date.now()
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
} catch (_) {}
|
|
799
|
+
|
|
772
800
|
ctx._reconnectTimer = setTimeout(() => {
|
|
773
801
|
ctx._reconnectTimer = null;
|
|
774
802
|
getSeqIDWrapper();
|
|
@@ -1080,7 +1108,8 @@ module.exports = (defaultFuncs, api, ctx, opts) => {
|
|
|
1080
1108
|
try {
|
|
1081
1109
|
const LIFECYCLE_EVENTS = [
|
|
1082
1110
|
'sessionExpired', 'checkpoint', 'relogin', 'ready',
|
|
1083
|
-
'account_inactive', 'checkpoint_282', 'checkpoint_956', 'error'
|
|
1111
|
+
'account_inactive', 'checkpoint_282', 'checkpoint_956', 'error',
|
|
1112
|
+
'reconnecting', 'reconnected', 'connected', 'disconnected'
|
|
1084
1113
|
];
|
|
1085
1114
|
for (const event of LIFECYCLE_EVENTS) {
|
|
1086
1115
|
// Use listeners() NOT rawListeners() — rawListeners() returns the
|
|
@@ -1149,8 +1178,64 @@ module.exports = (defaultFuncs, api, ctx, opts) => {
|
|
|
1149
1178
|
|
|
1150
1179
|
ctx.firstListen = false;
|
|
1151
1180
|
|
|
1152
|
-
api.stopListening = msgEmitter.stopListening;
|
|
1153
|
-
api.stopListeningAsync = msgEmitter.stopListeningAsync;
|
|
1181
|
+
api.stopListening = msgEmitter.stopListening.bind(msgEmitter);
|
|
1182
|
+
api.stopListeningAsync = msgEmitter.stopListeningAsync.bind(msgEmitter);
|
|
1183
|
+
|
|
1184
|
+
api.reconnect = function(callback) {
|
|
1185
|
+
let resolveFunc, rejectFunc;
|
|
1186
|
+
const returnPromise = new Promise((resolve, reject) => {
|
|
1187
|
+
resolveFunc = resolve;
|
|
1188
|
+
rejectFunc = reject;
|
|
1189
|
+
});
|
|
1190
|
+
const cb = typeof callback === "function"
|
|
1191
|
+
? (err) => { callback(err); if (err) rejectFunc(err); else resolveFunc(); }
|
|
1192
|
+
: (err) => { if (err) rejectFunc(err); else resolveFunc(); };
|
|
1193
|
+
|
|
1194
|
+
if (ctx._ending) {
|
|
1195
|
+
return cb(new Error("listenMqtt is not active — call listenMqtt() first")), returnPromise;
|
|
1196
|
+
}
|
|
1197
|
+
utils.log("MQTT", "api.reconnect() — force-reconnecting");
|
|
1198
|
+
try { if (ctx.mqttClient) ctx.mqttClient.end(true); } catch (_) {}
|
|
1199
|
+
ctx._mqttConnected = false;
|
|
1200
|
+
ctx._reconnectAttempts = 0;
|
|
1201
|
+
if (ctx._reconnectTimer) {
|
|
1202
|
+
clearTimeout(ctx._reconnectTimer);
|
|
1203
|
+
ctx._reconnectTimer = null;
|
|
1204
|
+
}
|
|
1205
|
+
try {
|
|
1206
|
+
if (ctx._emitter) ctx._emitter.emit('reconnecting', { forced: true, attempt: 0, delayMs: 0, timestamp: Date.now() });
|
|
1207
|
+
} catch (_) {}
|
|
1208
|
+
getSeqIDWrapper().then(() => cb(null)).catch(cb);
|
|
1209
|
+
return returnPromise;
|
|
1210
|
+
};
|
|
1211
|
+
|
|
1212
|
+
api.getReconnectStatus = function() {
|
|
1213
|
+
const stats = ctx._reconnectStats || {};
|
|
1214
|
+
return {
|
|
1215
|
+
connected: !!(ctx.mqttClient && ctx.mqttClient.connected),
|
|
1216
|
+
reconnectAttempts: ctx._reconnectAttempts || 0,
|
|
1217
|
+
totalReconnects: stats.totalAttempts || 0,
|
|
1218
|
+
lastAttemptAt: stats.lastAttemptAt || null,
|
|
1219
|
+
nextAttemptAt: ctx._reconnectTimer ? (stats.nextAttemptAt || null) : null,
|
|
1220
|
+
lastSuccessAt: stats.lastSuccessAt || null,
|
|
1221
|
+
reconnectPending: !!ctx._reconnectTimer,
|
|
1222
|
+
autoReconnect: !!ctx.globalOptions.autoReconnect,
|
|
1223
|
+
options: Object.assign({}, ctx._mqttOpt || {})
|
|
1224
|
+
};
|
|
1225
|
+
};
|
|
1226
|
+
|
|
1227
|
+
api.setReconnectOptions = function(newOpts) {
|
|
1228
|
+
if (!newOpts || typeof newOpts !== "object") return;
|
|
1229
|
+
ctx._mqttOpt = Object.assign({}, MQTT_DEFAULTS, ctx._mqttOpt || {}, newOpts);
|
|
1230
|
+
if (typeof ctx._mqttOpt.autoReconnect === "boolean") {
|
|
1231
|
+
ctx.globalOptions.autoReconnect = ctx._mqttOpt.autoReconnect;
|
|
1232
|
+
}
|
|
1233
|
+
if (typeof ctx._mqttOpt.cycleMs === "number") {
|
|
1234
|
+
conf = Object.assign({}, conf, { cycleMs: ctx._mqttOpt.cycleMs });
|
|
1235
|
+
}
|
|
1236
|
+
utils.log("MQTT", "setReconnectOptions applied:", JSON.stringify(ctx._mqttOpt));
|
|
1237
|
+
return ctx._mqttOpt;
|
|
1238
|
+
};
|
|
1154
1239
|
|
|
1155
1240
|
api.useMiddleware = function(nameOrFn, fn) {
|
|
1156
1241
|
const remove = ctx._middleware.use(nameOrFn, fn);
|
package/src/apis/markAsRead.js
CHANGED
|
@@ -21,7 +21,18 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
21
21
|
|
|
22
22
|
if (!callback) {
|
|
23
23
|
callback = (err) => {
|
|
24
|
-
if (err) return rejectFunc(err instanceof Error ? err : new Error(String(err.error || err.message || err)));
|
|
24
|
+
if (err) return rejectFunc(err instanceof Error ? err : new Error(String(err && (err.error || err.message) || err)));
|
|
25
|
+
resolveFunc(null);
|
|
26
|
+
};
|
|
27
|
+
} else {
|
|
28
|
+
const _userCb = callback;
|
|
29
|
+
callback = (err) => {
|
|
30
|
+
if (err) {
|
|
31
|
+
const e = err instanceof Error ? err : new Error(String(err && (err.error || err.message) || err));
|
|
32
|
+
_userCb(e);
|
|
33
|
+
return rejectFunc(e);
|
|
34
|
+
}
|
|
35
|
+
_userCb(null);
|
|
25
36
|
resolveFunc(null);
|
|
26
37
|
};
|
|
27
38
|
}
|
|
@@ -43,9 +54,7 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
43
54
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
44
55
|
|
|
45
56
|
if (resData && resData.error) {
|
|
46
|
-
|
|
47
|
-
callback(err);
|
|
48
|
-
return returnPromise;
|
|
57
|
+
return callback(new Error(String(resData.error.message || resData.error)));
|
|
49
58
|
}
|
|
50
59
|
|
|
51
60
|
callback(null);
|
|
@@ -62,16 +71,13 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
62
71
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
63
72
|
|
|
64
73
|
if (resData && resData.error) {
|
|
65
|
-
|
|
66
|
-
callback(err);
|
|
67
|
-
return returnPromise;
|
|
74
|
+
return callback(new Error(String(resData.error.message || resData.error)));
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
callback(null);
|
|
71
78
|
}
|
|
72
79
|
} catch (e) {
|
|
73
|
-
|
|
74
|
-
callback(err);
|
|
80
|
+
callback(e instanceof Error ? e : new Error(String(e && (e.error || e.message) || e)));
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
return returnPromise;
|
package/src/apis/muteThread.js
CHANGED
|
@@ -31,7 +31,7 @@ module.exports = (defaultFuncs, api, ctx) => {
|
|
|
31
31
|
).then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
32
32
|
|
|
33
33
|
if (res && res.error) {
|
|
34
|
-
throw res;
|
|
34
|
+
throw new Error(res.error_msg || res.errorSummary || String(res.error));
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
callback(null, { success: true });
|
package/src/apis/nickname.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const utils = require('../utils');
|
|
4
4
|
const { publishLsRequestWithAck, buildLsTask, generateEpochId } = require('../utils/lsRequest');
|
|
5
5
|
|
|
6
|
-
const NICKNAME_VERSION_ID = "
|
|
6
|
+
const NICKNAME_VERSION_ID = "8798795233522156";
|
|
7
7
|
|
|
8
8
|
module.exports = function (defaultFuncs, api, ctx) {
|
|
9
9
|
/**
|
package/src/apis/pinMessage.js
CHANGED
|
@@ -1,152 +1,132 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const utils = require('../utils');
|
|
4
|
-
const fs = require("fs");
|
|
5
|
-
const path = require("path");
|
|
6
|
-
const _ = require("lodash");
|
|
7
|
-
const deepdash = require("deepdash");
|
|
8
|
-
const { JSONPath } = require("jsonpath-plus");
|
|
3
|
+
const utils = require('../utils');
|
|
9
4
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* @returns {Object|null} The full lightspeed_web_request object or null.
|
|
18
|
-
*/
|
|
19
|
-
function extractAndSearchLightspeedRequest(allJsonData, options = {}) {
|
|
20
|
-
const { saveDebugFile = false, debugFilePath } = options;
|
|
21
|
-
|
|
22
|
-
let outputFile = null;
|
|
23
|
-
if (saveDebugFile && debugFilePath) {
|
|
24
|
-
outputFile = debugFilePath;
|
|
25
|
-
} else if (saveDebugFile) {
|
|
26
|
-
// Only save to current working directory if explicitly requested
|
|
27
|
-
outputFile = require('path').join(process.cwd(), "fca_neo_pro_lightspeed_debug.json");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const lightReq = _.get(allJsonData, "__bbox.result.data.viewer.lightspeed_web_request");
|
|
31
|
-
if (!lightReq) {
|
|
32
|
-
utils.warn("pin.js: lightspeed_web_request not found.");
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (outputFile) {
|
|
38
|
-
try {
|
|
39
|
-
fs.writeFileSync(outputFile, JSON.stringify(lightReq, null, 2), "utf8");
|
|
40
|
-
utils.log(`pin.js: Saved lightspeed_web_request to ${outputFile}`);
|
|
41
|
-
} catch (err) {
|
|
42
|
-
utils.error("pin.js: Failed to write lightspeed_web_request.json", err);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
const matches = JSONPath({
|
|
49
|
-
path: `$..[?(@ === "setPinnedMessage" || @ === "deleteThenInsertMessage")]`,
|
|
50
|
-
json: lightReq
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
utils.log(`pin.js: Found ${matches.length} matching command(s).`);
|
|
54
|
-
matches.forEach((match, idx) => {
|
|
55
|
-
utils.log(`📌 Match ${idx + 1}:`, match);
|
|
5
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
6
|
+
return async function pin(action, threadID, messageID, callback) {
|
|
7
|
+
let resolveFunc = () => {};
|
|
8
|
+
let rejectFunc = () => {};
|
|
9
|
+
const returnPromise = new Promise((resolve, reject) => {
|
|
10
|
+
resolveFunc = resolve;
|
|
11
|
+
rejectFunc = reject;
|
|
56
12
|
});
|
|
57
|
-
} catch (err) {
|
|
58
|
-
utils.error("pin.js: JSONPath search failed.", err);
|
|
59
|
-
}
|
|
60
13
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
14
|
+
if (!callback) {
|
|
15
|
+
callback = (err, result) => {
|
|
16
|
+
if (err) return rejectFunc(err);
|
|
17
|
+
resolveFunc(result);
|
|
18
|
+
};
|
|
19
|
+
} else {
|
|
20
|
+
const _userCb = callback;
|
|
21
|
+
callback = (err, result) => {
|
|
22
|
+
if (err) { _userCb(err); return rejectFunc(err); }
|
|
23
|
+
_userCb(null, result);
|
|
24
|
+
resolveFunc(result);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
68
27
|
|
|
69
|
-
|
|
28
|
+
try {
|
|
29
|
+
if (action === "list") {
|
|
30
|
+
if (!threadID) throw new Error('Action "list" requires threadID.');
|
|
70
31
|
const url = `https://www.facebook.com/messages/t/${threadID}/`;
|
|
71
32
|
const allJsonData = await utils.json(url, ctx.jar, null, ctx.globalOptions, ctx);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
33
|
+
const lightReq = allJsonData && allJsonData.__bbox &&
|
|
34
|
+
allJsonData.__bbox.result &&
|
|
35
|
+
allJsonData.__bbox.result.data &&
|
|
36
|
+
allJsonData.__bbox.result.data.viewer &&
|
|
37
|
+
allJsonData.__bbox.result.data.viewer.lightspeed_web_request;
|
|
75
38
|
if (!lightReq || !lightReq.pin_status) {
|
|
76
|
-
utils.warn("
|
|
77
|
-
return [];
|
|
39
|
+
utils.warn("pinMessage: No pinned messages found or pin_status missing.");
|
|
40
|
+
return callback(null, []);
|
|
78
41
|
}
|
|
79
|
-
return lightReq;
|
|
80
|
-
} catch (err) {
|
|
81
|
-
utils.error(`pin.js: Failed to process "list" for thread ${threadID}`, err);
|
|
82
|
-
throw err;
|
|
42
|
+
return callback(null, lightReq);
|
|
83
43
|
}
|
|
84
|
-
}
|
|
85
44
|
|
|
86
|
-
|
|
87
|
-
|
|
45
|
+
if (!ctx.mqttClient || !ctx.mqttClient.connected) {
|
|
46
|
+
throw new Error("MQTT not connected — call listenMqtt() first.");
|
|
47
|
+
}
|
|
48
|
+
if (!threadID || !messageID) {
|
|
49
|
+
throw new Error(`"${action}" requires threadID and messageID.`);
|
|
50
|
+
}
|
|
88
51
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const app_id = "2220391788200892";
|
|
52
|
+
if (typeof ctx.wsReqNumber !== "number") ctx.wsReqNumber = 0;
|
|
53
|
+
if (typeof ctx.wsTaskNumber !== "number") ctx.wsTaskNumber = 0;
|
|
92
54
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
request_id: (ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1),
|
|
97
|
-
type: 3
|
|
98
|
-
});
|
|
55
|
+
const epoch_id = parseInt(utils.generateOfflineThreadingID());
|
|
56
|
+
const version_id = "9523201934447612";
|
|
57
|
+
const app_id = String(ctx.appID || ctx.mqttAppID || "2220391788200892");
|
|
99
58
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
59
|
+
const createMqttRequest = (tasks, increment = 0) => ({
|
|
60
|
+
app_id,
|
|
61
|
+
payload: JSON.stringify({ epoch_id: epoch_id + increment, tasks, version_id }),
|
|
62
|
+
request_id: ++ctx.wsReqNumber,
|
|
63
|
+
type: 3
|
|
106
64
|
});
|
|
107
65
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const setSearchTask = {
|
|
116
|
-
label: "751",
|
|
117
|
-
payload: JSON.stringify({ thread_key: threadID, message_id: messageID, pinned_message_state: 1 }),
|
|
118
|
-
queue_name: "set_pinned_message_search",
|
|
119
|
-
task_id: (ctx.wsTaskNumber = (ctx.wsTaskNumber || 0) + 1)
|
|
120
|
-
};
|
|
121
|
-
const req1 = createMqttRequest([pinTask], 0);
|
|
122
|
-
const req2 = createMqttRequest([setSearchTask], 1);
|
|
123
|
-
return Promise.all([publishMqtt(req1), publishMqtt(req2)]);
|
|
124
|
-
}
|
|
66
|
+
const publishMqtt = (content) =>
|
|
67
|
+
new Promise((resolve, reject) => {
|
|
68
|
+
ctx.mqttClient.publish("/ls_req", JSON.stringify(content), { qos: 1, retain: false }, (err) => {
|
|
69
|
+
if (err) reject(err instanceof Error ? err : new Error(String(err)));
|
|
70
|
+
else resolve({ success: true, request_id: content.request_id });
|
|
71
|
+
});
|
|
72
|
+
});
|
|
125
73
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
74
|
+
if (action === "pin") {
|
|
75
|
+
const pinTask = {
|
|
76
|
+
failure_count: null,
|
|
77
|
+
label: "430",
|
|
78
|
+
payload: JSON.stringify({ thread_key: threadID, message_id: messageID, timestamp_ms: Date.now() }),
|
|
79
|
+
queue_name: `pin_msg_v2_${threadID}`,
|
|
80
|
+
task_id: ++ctx.wsTaskNumber
|
|
81
|
+
};
|
|
82
|
+
const setSearchTask = {
|
|
83
|
+
failure_count: null,
|
|
84
|
+
label: "751",
|
|
85
|
+
payload: JSON.stringify({ thread_key: threadID, message_id: messageID, pinned_message_state: 1 }),
|
|
86
|
+
queue_name: "set_pinned_message_search",
|
|
87
|
+
task_id: ++ctx.wsTaskNumber
|
|
88
|
+
};
|
|
89
|
+
const results = await Promise.all([
|
|
90
|
+
publishMqtt(createMqttRequest([pinTask], 0)),
|
|
91
|
+
publishMqtt(createMqttRequest([setSearchTask], 1))
|
|
92
|
+
]);
|
|
93
|
+
return callback(null, { success: true, action: "pin", results });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (action === "unpin") {
|
|
97
|
+
const setSearchTask1 = {
|
|
98
|
+
failure_count: null,
|
|
99
|
+
label: "751",
|
|
100
|
+
payload: JSON.stringify({ thread_key: threadID, message_id: messageID, pinned_message_state: 0 }),
|
|
101
|
+
queue_name: "set_pinned_message_search",
|
|
102
|
+
task_id: ++ctx.wsTaskNumber
|
|
103
|
+
};
|
|
104
|
+
const unpinTask = {
|
|
105
|
+
failure_count: null,
|
|
106
|
+
label: "431",
|
|
107
|
+
payload: JSON.stringify({ thread_key: threadID, message_id: messageID, timestamp_ms: Date.now() }),
|
|
108
|
+
queue_name: `unpin_msg_v2_${threadID}`,
|
|
109
|
+
task_id: ++ctx.wsTaskNumber
|
|
110
|
+
};
|
|
111
|
+
const setSearchTask2 = {
|
|
112
|
+
failure_count: null,
|
|
113
|
+
label: "751",
|
|
114
|
+
payload: JSON.stringify({ thread_key: threadID, message_id: messageID, pinned_message_state: 0 }),
|
|
115
|
+
queue_name: "set_pinned_message_search",
|
|
116
|
+
task_id: ++ctx.wsTaskNumber
|
|
117
|
+
};
|
|
118
|
+
await publishMqtt(createMqttRequest([setSearchTask1], 0));
|
|
119
|
+
await publishMqtt(createMqttRequest([unpinTask], 1));
|
|
120
|
+
const result = await publishMqtt(createMqttRequest([setSearchTask2], 2));
|
|
121
|
+
return callback(null, { success: true, action: "unpin", result });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
throw new Error(`Invalid action: "${action}". Use "pin", "unpin", or "list".`);
|
|
125
|
+
} catch (err) {
|
|
126
|
+
utils.error("pinMessage", err);
|
|
127
|
+
callback(err instanceof Error ? err : new Error(String(err && err.message ? err.message : err)));
|
|
148
128
|
}
|
|
149
129
|
|
|
150
|
-
|
|
130
|
+
return returnPromise;
|
|
151
131
|
};
|
|
152
132
|
};
|
|
@@ -52,7 +52,7 @@ module.exports = (defaultFuncs, api, ctx) => {
|
|
|
52
52
|
task_id: taskID
|
|
53
53
|
}
|
|
54
54
|
],
|
|
55
|
-
version_id: '
|
|
55
|
+
version_id: '25002366262773827'
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
const form = JSON.stringify({
|
|
@@ -110,7 +110,7 @@ module.exports = (defaultFuncs, api, ctx) => {
|
|
|
110
110
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs));
|
|
111
111
|
|
|
112
112
|
if (!res || res.error) {
|
|
113
|
-
throw res ||
|
|
113
|
+
throw new Error((res && (res.error_msg || res.errorSummary || String(res.error))) || "Remove from group failed");
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
callback(null, { success: true });
|
|
@@ -41,7 +41,7 @@ photo_id: photoID,
|
|
|
41
41
|
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
42
42
|
.then((resData) => {
|
|
43
43
|
if (resData.error) {
|
|
44
|
-
throw resData;
|
|
44
|
+
throw new Error(resData.error_msg || resData.errorSummary || String(resData.error));
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const photoUrl = resData.jsmods.require[0][3][0];
|
|
@@ -113,7 +113,7 @@ module.exports = (defaultFuncs, api, ctx) => {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
if (res.error) {
|
|
116
|
-
throw res;
|
|
116
|
+
throw new Error(res.error_msg || res.errorSummary || String(res.error));
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
// Support both legacy payload.threads (object map) and newer payload.mercury_payload.threads (array)
|
package/src/apis/sendMessage.js
CHANGED
|
@@ -250,6 +250,13 @@ module.exports = (defaultFuncs, api, ctx) => {
|
|
|
250
250
|
if (err) return rejectFunc(err);
|
|
251
251
|
resolveFunc(data);
|
|
252
252
|
};
|
|
253
|
+
} else {
|
|
254
|
+
const _userCb = callback;
|
|
255
|
+
callback = (err, data) => {
|
|
256
|
+
if (err) { _userCb(err); return rejectFunc(err); }
|
|
257
|
+
_userCb(null, data);
|
|
258
|
+
resolveFunc(data);
|
|
259
|
+
};
|
|
253
260
|
}
|
|
254
261
|
|
|
255
262
|
let msgType = utils.getType(msg);
|
|
@@ -35,8 +35,9 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
35
35
|
const defData = await defaultFuncs.postFormData(
|
|
36
36
|
"https://www.facebook.com/webgraphql/mutation/",
|
|
37
37
|
ctx.jar,
|
|
38
|
+
{},
|
|
38
39
|
{
|
|
39
|
-
doc_id: "
|
|
40
|
+
doc_id: "1491398900900362",
|
|
40
41
|
variables: JSON.stringify({
|
|
41
42
|
data: {
|
|
42
43
|
client_mutation_id: ctx.clientMutationId++,
|
|
@@ -47,8 +48,7 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
47
48
|
}
|
|
48
49
|
}),
|
|
49
50
|
dpr: 1
|
|
50
|
-
}
|
|
51
|
-
{}
|
|
51
|
+
}
|
|
52
52
|
);
|
|
53
53
|
|
|
54
54
|
const resData = await utils.parseAndCheckLogin(ctx, defaultFuncs)(defData);
|
|
@@ -50,7 +50,7 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
50
50
|
failure_count: null,
|
|
51
51
|
label: "29",
|
|
52
52
|
payload: JSON.stringify(taskPayload),
|
|
53
|
-
queue_name:
|
|
53
|
+
queue_name: `reaction:${messageID}`,
|
|
54
54
|
task_id: taskId
|
|
55
55
|
};
|
|
56
56
|
|
|
@@ -60,7 +60,7 @@ module.exports = function (defaultFuncs, api, ctx) {
|
|
|
60
60
|
data_trace_id: null,
|
|
61
61
|
epoch_id: parseInt(utils.generateOfflineThreadingID()),
|
|
62
62
|
tasks: [task],
|
|
63
|
-
version_id: "
|
|
63
|
+
version_id: "24585299697835063"
|
|
64
64
|
}),
|
|
65
65
|
request_id: requestId,
|
|
66
66
|
type: 3
|