UNPKG

ws3-fca

Version:

A node.js package for automating Facebook Messenger bot, and is one of the most advanced next-generation Facebook Chat API (FCA) by @NethWs3Dev & @ExocoreCommunity

244 lines (234 loc) 10.2 kB
"use strict"; const utils = require('../../../utils'); /** * @ChoruOfficial * @description A module for managing friend-related actions like listing friends, handling requests, and getting suggestions. * @param {Object} defaultFuncs The default functions provided by the API wrapper. * @param {Object} api The full API object. * @param {Object} ctx The context object containing the user's session state (e.g., userID, jar, fb_dtsg). * @returns {Object} A `friendModule` object with methods for friend interactions. */ module.exports = function (defaultFuncs, api, ctx) { /** * A private helper function to standardize friend data from various GraphQL endpoints. * @private * @param {Object} data The raw data object from a GraphQL response. * @param {('requests'|'suggestions'|'list')} type The type of data to format, which determines the path to the user list. * @returns {Array<Object>} An array of formatted friend objects, each containing `userID`, `name`, `profilePicture`, `socialContext`, and `url`. */ function formatFriends(data, type) { const viewer = data?.data?.viewer; let edges; if (type === 'requests' && viewer?.friend_requests?.edges) { edges = viewer.friend_requests.edges; } else if (type === 'suggestions' && viewer?.people_you_may_know?.edges) { edges = viewer.people_you_may_know.edges; } else if (type === 'list' && data?.data?.node?.all_collections?.nodes[0]?.style_renderer?.collection?.pageItems?.edges) { edges = data.data.node.all_collections.nodes[0].style_renderer.collection.pageItems.edges; } else { return []; } return edges.map(edge => { const node = edge.node; return { userID: node.id || node.node?.id, name: node.name || node.title?.text, profilePicture: node.profile_picture?.uri || node.image?.uri, socialContext: node.social_context?.text || node.subtitle_text?.text, url: node.url }; }); } const friendModule = { /** * @namespace api.friend * @description A collection of functions for interacting with friends. * @license Ex-it * @author ChoruOfficial */ /** * Fetches the list of incoming friend requests. * @async * @returns {Promise<Array<Object>>} A promise that resolves to an array of friend request objects. * @throws {Error} If the API request fails or returns an error. */ requests: async function() { try { const form = { av: ctx.userID, __user: ctx.userID, __a: "1", fb_dtsg: ctx.fb_dtsg, jazoest: ctx.jazoest, lsd: ctx.lsd, fb_api_caller_class: "RelayModern", fb_api_req_friendly_name: "FriendingCometRootContentQuery", variables: JSON.stringify({ scale: 3 }), doc_id: "9103543533085580" }; const res = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, {}); if (res.data.errors) throw new Error(JSON.stringify(res.data.errors)); return formatFriends(res.data, 'requests'); } catch (err) { throw err; } }, /** * Accepts a friend request. * @async * @param {string} identifier The user ID or name of the person whose friend request is to be accepted. If a name is provided, the function will search through pending requests. * @returns {Promise<Object>} A promise that resolves to the API response data upon successful acceptance. * @throws {Error} If the identifier is missing, the user is not found in requests, or the API call fails. */ accept: async function(identifier) { try { if (!identifier) throw new Error("A name or user ID is required."); let targetUserID = identifier; if (isNaN(identifier)) { const requests = await friendModule.requests(); const found = requests.find(req => req.name.toLowerCase().includes(identifier.toLowerCase())); if (!found) throw new Error(`Could not find any friend request matching "${identifier}".`); targetUserID = found.userID; } const variables = { input: { friend_requester_id: targetUserID, friending_channel: "FRIENDS_HOME_MAIN", actor_id: ctx.userID, client_mutation_id: Math.floor(Math.random() * 10 + 1).toString() }, scale: 3 }; const form = { av: ctx.userID, __user: ctx.userID, __a: "1", fb_dtsg: ctx.fb_dtsg, jazoest: ctx.jazoest, lsd: ctx.lsd, fb_api_caller_class: "RelayModern", fb_api_req_friendly_name: "FriendingCometFriendRequestConfirmMutation", variables: JSON.stringify(variables), doc_id: "24630768433181357" }; const res = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, {}); if (res.data.errors) throw new Error(JSON.stringify(res.data.errors)); return res.data.data; } catch (err) { if (err.message?.includes("1431004")) { throw new Error("I cannot accept this friend request right now. There might be a problem with the account or you need to wait."); } throw err; } }, /** * Fetches the friend list for a given user ID. * @async * @param {string} [userID=ctx.userID] The ID of the user whose friend list to fetch. Defaults to the logged-in user. * @returns {Promise<Array<Object>>} A promise that resolves to an array of formatted friend objects. * @throws {Error} If the API request fails. */ list: async function(userID = ctx.userID) { try { const sectionToken = Buffer.from(`app_section:${userID}:2356318349`).toString('base64'); const variables = { collectionToken: null, scale: 2, sectionToken: sectionToken, useDefaultActor: false, userID: userID }; const form = { av: ctx.userID, __user: ctx.userID, __a: "1", fb_dtsg: ctx.fb_dtsg, jazoest: ctx.jazoest, lsd: ctx.lsd, fb_api_caller_class: "RelayModern", fb_api_req_friendly_name: "ProfileCometTopAppSectionQuery", variables: JSON.stringify(variables), doc_id: "24492266383698794" }; const res = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, {}); if (res.data.errors) throw new Error(JSON.stringify(res.data.errors)); return formatFriends(res.data, 'list'); } catch(err) { throw err; } }, /** * @namespace api.friend.suggest * @description Functions for managing friend suggestions. */ suggest: { /** * Fetches a list of suggested friends (People You May Know). * @async * @param {number} [limit=30] The maximum number of suggestions to fetch. * @returns {Promise<Array<Object>>} A promise that resolves to an array of suggested friend objects. * @throws {Error} If the API request fails. */ list: async function(limit = 30) { try { const form = { av: ctx.userID, __user: ctx.userID, __a: "1", fb_dtsg: ctx.fb_dtsg, jazoest: ctx.jazoest, lsd: ctx.lsd, fb_api_caller_class: "RelayModern", fb_api_req_friendly_name: "FriendingCometPYMKPanelPaginationQuery", variables: JSON.stringify({ count: limit, cursor: null, scale: 3 }), doc_id: "9917809191634193" }; const res = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, {}); if (res.data.errors) throw new Error(JSON.stringify(res.data.errors)); return formatFriends(res.data, 'suggestions'); } catch(err) { throw err; } }, /** * Sends a friend request to a user. * @async * @param {string} userID The ID of the user to send the friend request to. * @returns {Promise<Object>} A promise that resolves to the API response data on success. * @throws {Error} If the userID is missing or the API request fails. */ request: async function(userID) { try { if (!userID) throw new Error("userID is required."); const variables = { input: { friend_requestee_ids: [userID], friending_channel: "FRIENDS_HOME_MAIN", actor_id: ctx.userID, client_mutation_id: Math.floor(Math.random() * 10 + 1).toString() }, scale: 3 }; const form = { av: ctx.userID, __user: ctx.userID, __a: "1", fb_dtsg: ctx.fb_dtsg, jazoest: ctx.jazoest, lsd: ctx.lsd, fb_api_caller_class: "RelayModern", fb_api_req_friendly_name: "FriendingCometFriendRequestSendMutation", variables: JSON.stringify(variables), doc_id: "23982103144788355" }; const res = await defaultFuncs.post("https://www.facebook.com/api/graphql/", ctx.jar, form, {}); if (res.data.errors) throw new Error(JSON.stringify(res.data.errors)); return res.data.data; } catch(err) { throw err; } } } }; return friendModule; };