sagor-fca 0.0.18 → 0.0.20

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sagor-fca",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "Custom FCA build by SaGor (forked from fca-unofficial) with extended features and faster updates.",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -23,4 +23,5 @@ module.exports = function (defaultFuncs, api, ctx) {
23
23
  }
24
24
  };
25
25
  };
26
-
26
+
27
+
@@ -0,0 +1,65 @@
1
+ 'use strict';
2
+
3
+ const { generateOfflineThreadingID } = require('../utils');
4
+
5
+ function isCallable(func) {
6
+ return typeof func === 'function';
7
+ }
8
+
9
+ module.exports = function (defaultFuncs, api, ctx) {
10
+ return function sendMessageEffect(effectID, messageID, threadID, callback) {
11
+ if (!ctx.mqttClient) {
12
+ throw new Error('MQTT client is not connected');
13
+ }
14
+
15
+ if (!effectID || !messageID || !threadID) {
16
+ throw new Error('Missing required parameters');
17
+ }
18
+
19
+ ctx.wsReqNumber = (ctx.wsReqNumber || 0) + 1;
20
+ ctx.wsTaskNumber = (ctx.wsTaskNumber || 0) + 1;
21
+
22
+ const taskPayload = {
23
+ thread_key: threadID,
24
+ message_id: messageID,
25
+ actor_id: ctx.userID,
26
+ timestamp_ms: Date.now(),
27
+ effect_id: effectID,
28
+ sync_group: 1
29
+ };
30
+
31
+ const task = {
32
+ failure_count: null,
33
+ label: '46',
34
+ payload: JSON.stringify(taskPayload),
35
+ queue_name: 'effect',
36
+ task_id: ctx.wsTaskNumber
37
+ };
38
+
39
+ const content = {
40
+ app_id: '2220391788200892',
41
+ payload: JSON.stringify({
42
+ epoch_id: parseInt(generateOfflineThreadingID()),
43
+ tasks: [task],
44
+ version_id: '7158486590867448'
45
+ }),
46
+ request_id: ctx.wsReqNumber,
47
+ type: 3
48
+ };
49
+
50
+ if (isCallable(callback)) {
51
+ ctx.reqCallbacks = ctx.reqCallbacks || {};
52
+ ctx.reqCallbacks[ctx.wsReqNumber] = callback;
53
+ }
54
+
55
+ try {
56
+ ctx.mqttClient.publish('/ls_req', JSON.stringify(content), {
57
+ qos: 1,
58
+ retain: false
59
+ });
60
+ } catch (err) {
61
+ if (isCallable(callback)) callback(err);
62
+ else console.error('sendMessageEffect error:', err);
63
+ }
64
+ };
65
+ };
package/src/sendEffect.js DELETED
@@ -1,157 +0,0 @@
1
- "use strict";
2
-
3
- const utils = require("../utils");
4
-
5
- // ═══════════════════════════════════════════════════
6
- // sendEffect.js — for sagor-fca
7
- // Author: SaGor
8
- //
9
- // Usage:
10
- // api.sendEffect(effect, threadID, callback)
11
- // api.sendEffect("fire", threadID)
12
- // api.sendEffect("love", event.threadID, (err, info) => {})
13
- // await api.sendEffect("gift", event.threadID)
14
- //
15
- // 4 Confirmed effects (from Messenger "Send Effects" screen):
16
- // "love" / "hearts" → ❤️ Love (pink hearts)
17
- // "gift" → 🎁 Gift Wrap (blue ribbon box)
18
- // "wham" / "bam" → 💥 Wham! (dark impact effect)
19
- // "fire" → 🔥 Fire (orange fire flies)
20
- // ═══════════════════════════════════════════════════
21
-
22
- // Confirmed Facebook Messenger internal send_effect tag names
23
- const EFFECTS = {
24
- // ❤️ Love / Hearts — leftmost in Messenger UI
25
- love: "love_hearts",
26
- hearts: "love_hearts",
27
- heart: "love_hearts",
28
-
29
- // 🎁 Gift Wrap — 2nd in Messenger UI
30
- gift: "gift_wrap",
31
-
32
- // 💥 Wham! — 3rd in Messenger UI (dark brown)
33
- wham: "wham",
34
- bam: "wham",
35
-
36
- // 🔥 Fire — rightmost in Messenger UI
37
- fire: "fire_fly",
38
- };
39
-
40
- module.exports = function (defaultFuncs, api, ctx) {
41
-
42
- return function sendEffect(effect, threadID, callback) {
43
-
44
- // Promise support
45
- let resolveFunc, rejectFunc;
46
- const returnPromise = new Promise((resolve, reject) => {
47
- resolveFunc = resolve;
48
- rejectFunc = reject;
49
- });
50
-
51
- if (typeof callback !== "function") {
52
- callback = function (err, data) {
53
- if (err) return rejectFunc(err);
54
- resolveFunc(data);
55
- };
56
- }
57
-
58
- // Validate effect name
59
- const effectKey = (effect || "").toString().toLowerCase().trim();
60
- const effectTag = EFFECTS[effectKey];
61
-
62
- if (!effectTag) {
63
- const valid = [...new Set(Object.values(EFFECTS).map(v =>
64
- Object.keys(EFFECTS).find(k => EFFECTS[k] === v)
65
- ))].join(", ");
66
- return callback({
67
- error: `Invalid effect "${effect}". Valid: ${valid}`
68
- });
69
- }
70
-
71
- // Validate threadID
72
- if (!threadID) {
73
- return callback({ error: "threadID is required." });
74
- }
75
-
76
- // Build the form — same base as sendMessage.js
77
- const messageAndOTID = utils.generateOfflineThreadingID();
78
-
79
- const form = {
80
- client: "mercury",
81
- action_type: "ma-type:user-generated-message",
82
- author: "fbid:" + ctx.userID,
83
- timestamp: Date.now(),
84
- timestamp_absolute: "Today",
85
- timestamp_relative: utils.generateTimestampRelative(),
86
- timestamp_time_passed: "0",
87
- is_unread: false,
88
- is_cleared: false,
89
- is_forward: false,
90
- is_filtered_content: false,
91
- is_filtered_content_bh: false,
92
- is_filtered_content_account: false,
93
- is_filtered_content_quasar: false,
94
- is_filtered_content_invalid_app: false,
95
- is_spoof_warning: false,
96
- source: "source:chat:web",
97
- "source_tags[0]": "source:chat",
98
- body: "",
99
- html_body: false,
100
- ui_push_phase: "V3",
101
- status: "0",
102
- offline_threading_id: messageAndOTID,
103
- message_id: messageAndOTID,
104
- threading_id: utils.generateThreadingID(ctx.clientID),
105
- "ephemeral_ttl_mode:": "0",
106
- manual_retry_cnt: "0",
107
- has_attachment: false,
108
- signatureID: utils.getSignatureID(),
109
-
110
- // KEY: same pattern as hot_emoji_size in sendMessage.js
111
- // form["tags[0]"] = "hot_emoji_size:large" ← for emoji
112
- // form["tags[0]"] = "send_effect:fire_fly" ← for effects
113
- "tags[0]": "send_effect:" + effectTag,
114
- };
115
-
116
- // Set thread target — same logic as sendMessage.js
117
- const threadIDStr = threadID.toString();
118
- const isDM = threadIDStr.length === 15 || !threadIDStr.match(/^\d{16,}$/);
119
-
120
- if (isDM) {
121
- form["specific_to_list[0]"] = "fbid:" + threadID;
122
- form["specific_to_list[1]"] = "fbid:" + ctx.userID;
123
- form["other_user_fbid"] = threadID;
124
- } else {
125
- form["thread_fbid"] = threadID;
126
- }
127
-
128
- // POST to messaging/send — same endpoint as sendMessage.js
129
- defaultFuncs
130
- .post("https://www.facebook.com/messaging/send/", ctx.jar, form)
131
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
132
- .then(function (resData) {
133
- if (!resData) {
134
- throw { error: "sendEffect: empty response." };
135
- }
136
- if (resData.error) {
137
- throw resData;
138
- }
139
- const actions = resData.payload && resData.payload.actions;
140
- const messageInfo = Array.isArray(actions)
141
- ? actions.reduce((p, v) => ({
142
- threadID: v.thread_fbid,
143
- messageID: v.message_id,
144
- timestamp: v.timestamp,
145
- }) || p, null)
146
- : null;
147
-
148
- return callback(null, messageInfo);
149
- })
150
- .catch(function (err) {
151
- console.error("sendEffect error:", err);
152
- return callback(err);
153
- });
154
-
155
- return returnPromise;
156
- };
157
- };