bb-fca 2.0.6 → 2.0.8

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.
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = searchGroupsModule;
4
+ const utils = require("../../../utils");
5
+ /**
6
+ * @description A module for searching Facebook groups by keyword.
7
+ * Calls SearchCometResultsPaginatedResultsQuery via /api/graphql/.
8
+ * @param {Object} defaultFuncs The default functions provided by the API wrapper.
9
+ * @param {Object} api The full API object.
10
+ * @param {Object} ctx The context object containing the user's session state.
11
+ * @returns {Function} An async function that searches for groups by keyword.
12
+ */
13
+ function searchGroupsModule(defaultFuncs, api, ctx) {
14
+ /**
15
+ * Generates a UUID v4 string for use as a batch search ID.
16
+ */
17
+ function createBsid() {
18
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
19
+ const r = Math.random() * 16;
20
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
21
+ return Math.floor(v).toString(16);
22
+ });
23
+ }
24
+ /**
25
+ * Parses a localised member count string (e.g. "1.2K members") into a number.
26
+ */
27
+ function parseLocalizedCount(text) {
28
+ const match = text.match(/([\d.,]+)\s*([kKmMbB])?/);
29
+ if (!match)
30
+ return null;
31
+ const base = Number((match[1] || '').replace(/,/g, '.'));
32
+ if (Number.isNaN(base))
33
+ return null;
34
+ const unit = (match[2] || '').toLowerCase();
35
+ if (unit === 'k')
36
+ return Math.round(base * 1000);
37
+ if (unit === 'm')
38
+ return Math.round(base * 1000000);
39
+ if (unit === 'b')
40
+ return Math.round(base * 1000000000);
41
+ return Math.round(base);
42
+ }
43
+ /**
44
+ * Maps a single search result edge to a group object.
45
+ */
46
+ function mapSearchGroupEdge(edge) {
47
+ const viewModel = edge?.rendering_strategy?.view_model;
48
+ const profile = viewModel?.profile || {};
49
+ const primaryCTAProfile = viewModel?.ctas?.primary?.[0]?.profile || {};
50
+ const summaryText = viewModel?.primary_snippet_text_with_entities?.text || null;
51
+ const summaryParts = summaryText
52
+ ? summaryText
53
+ .split('·')
54
+ .map((part) => part.trim())
55
+ .filter(Boolean)
56
+ : [];
57
+ const memberPart = summaryParts.find((part) => /member|thành viên|membro|mitglieder|membres/i.test(part)) || null;
58
+ return {
59
+ groupID: profile.id || null,
60
+ name: profile.name || null,
61
+ url: profile.url || primaryCTAProfile.url || null,
62
+ profileUrl: profile.profile_url || profile.url || primaryCTAProfile.url || null,
63
+ imageSrc: profile.profile_picture?.uri || null,
64
+ summary: summaryText,
65
+ privacy: summaryParts[0] || null,
66
+ memberText: memberPart,
67
+ memberCount: memberPart ? parseLocalizedCount(memberPart) : null,
68
+ joinState: primaryCTAProfile.viewer_join_state || null,
69
+ hasMembershipQuestions: typeof primaryCTAProfile.has_membership_questions === 'boolean'
70
+ ? primaryCTAProfile.has_membership_questions
71
+ : null,
72
+ };
73
+ }
74
+ /**
75
+ * Parses the HTTP response body, handling both pre-parsed objects and raw strings.
76
+ */
77
+ function parseResponseBody(body) {
78
+ if (typeof body === 'object' && body !== null && !Buffer.isBuffer(body)) {
79
+ return body;
80
+ }
81
+ const raw = typeof body === 'string' ? body : body.toString();
82
+ const normalized = raw.replace(/^for \(;;\);\s*/, '');
83
+ try {
84
+ return JSON.parse(normalized);
85
+ }
86
+ catch {
87
+ const lines = normalized.split('\n').filter(Boolean);
88
+ return JSON.parse(lines[0]);
89
+ }
90
+ }
91
+ /**
92
+ * Searches for Facebook groups matching the given keyword.
93
+ * Uses Facebook's Search Comet endpoint with GROUPS_TAB_GLOBAL experience.
94
+ * @async
95
+ * @param {string} keyword The search keyword.
96
+ * @param {Object} [options] Optional parameters.
97
+ * @param {number} [options.limit=10] Number of results per page.
98
+ * @param {string|null} [options.cursor=null] Pagination cursor from a previous result.
99
+ * @param {string} [options.locale='vi_VN'] Locale for the search request.
100
+ * @returns {Promise<{ groups: any[]; cursor: string | null; hasNextPage: boolean }>}
101
+ * @throws {Error} If the keyword is missing or the API request fails.
102
+ *
103
+ * @example
104
+ * const result = await api.searchGroups('gaming');
105
+ * console.log(result.groups); // Array of group objects
106
+ * console.log(result.cursor); // cursor string for next page
107
+ * console.log(result.hasNextPage);
108
+ *
109
+ * // Page 2
110
+ * const page2 = await api.searchGroups('gaming', { cursor: result.cursor });
111
+ */
112
+ return async function searchGroups(keyword, options = {}) {
113
+ if (!keyword || typeof keyword !== 'string') {
114
+ throw new Error('searchGroups: keyword must be a non-empty string.');
115
+ }
116
+ const limit = typeof options.limit === 'number' && Number.isInteger(options.limit)
117
+ ? options.limit
118
+ : 10;
119
+ if (limit <= 0) {
120
+ throw new Error('searchGroups: options.limit must be a positive integer.');
121
+ }
122
+ const locale = options.locale || 'vi_VN';
123
+ const bsid = createBsid();
124
+ const tsid = Math.random().toString();
125
+ const variables = {
126
+ allow_streaming: false,
127
+ args: {
128
+ callsite: 'comet:groups_search',
129
+ config: {
130
+ exact_match: false,
131
+ high_confidence_config: null,
132
+ intercept_config: null,
133
+ sts_disambiguation: null,
134
+ watch_config: null,
135
+ },
136
+ context: {
137
+ bsid,
138
+ tsid,
139
+ },
140
+ experience: {
141
+ client_defined_experiences: ['ADS_PARALLEL_FETCH'],
142
+ encoded_server_defined_params: null,
143
+ fbid: null,
144
+ type: 'GROUPS_TAB_GLOBAL',
145
+ },
146
+ filters: [],
147
+ text: keyword,
148
+ },
149
+ count: limit,
150
+ cursor: options.cursor ?? null,
151
+ feedLocation: 'SEARCH',
152
+ feedbackSource: 23,
153
+ fetch_filters: true,
154
+ focusCommentID: null,
155
+ locale: null,
156
+ privacySelectorRenderLocation: 'COMET_STREAM',
157
+ referringStoryRenderLocation: null,
158
+ renderLocation: 'search_results_page',
159
+ scale: 1,
160
+ stream_initial_count: 0,
161
+ useDefaultActor: false,
162
+ __relay_internal__pv__GHLShouldChangeAdIdFieldNamerelayprovider: true,
163
+ __relay_internal__pv__GHLShouldChangeSponsoredDataFieldNamerelayprovider: true,
164
+ __relay_internal__pv__CometFeedStory_enable_post_permalink_white_space_clickrelayprovider: false,
165
+ __relay_internal__pv__CometUFICommentActionLinksRewriteEnabledrelayprovider: false,
166
+ __relay_internal__pv__CometUFICommentAvatarStickerAnimatedImagerelayprovider: false,
167
+ __relay_internal__pv__IsWorkUserrelayprovider: false,
168
+ __relay_internal__pv__TestPilotShouldIncludeDemoAdUseCaserelayprovider: false,
169
+ __relay_internal__pv__FBReels_deprecate_short_form_video_context_gkrelayprovider: true,
170
+ __relay_internal__pv__FBReels_enable_view_dubbed_audio_type_gkrelayprovider: true,
171
+ __relay_internal__pv__CometImmersivePhotoCanUserDisable3DMotionrelayprovider: false,
172
+ __relay_internal__pv__WorkCometIsEmployeeGKProviderrelayprovider: false,
173
+ __relay_internal__pv__IsMergQAPollsrelayprovider: false,
174
+ __relay_internal__pv__FBReelsMediaFooter_comet_enable_reels_ads_gkrelayprovider: true,
175
+ __relay_internal__pv__CometUFIReactionsEnableShortNamerelayprovider: false,
176
+ __relay_internal__pv__CometUFICommentAutoTranslationTyperelayprovider: 'ORIGINAL',
177
+ __relay_internal__pv__CometUFIShareActionMigrationrelayprovider: true,
178
+ __relay_internal__pv__CometUFISingleLineUFIrelayprovider: false,
179
+ __relay_internal__pv__CometUFI_dedicated_comment_routable_dialog_gkrelayprovider: true,
180
+ __relay_internal__pv__FBReelsIFUTileContent_reelsIFUPlayOnHoverrelayprovider: true,
181
+ __relay_internal__pv__GroupsCometGYSJFeedItemHeightrelayprovider: 150,
182
+ __relay_internal__pv__ShouldEnableBakedInTextStoriesrelayprovider: false,
183
+ __relay_internal__pv__StoriesShouldIncludeFbNotesrelayprovider: false,
184
+ };
185
+ const form = {
186
+ av: ctx.i_userID || ctx.userID,
187
+ __user: ctx.i_userID || ctx.userID,
188
+ __a: '1',
189
+ fb_dtsg: ctx.fb_dtsg,
190
+ jazoest: ctx.jazoest,
191
+ lsd: ctx.lsd || '',
192
+ locale,
193
+ fb_api_caller_class: 'RelayModern',
194
+ fb_api_req_friendly_name: 'SearchCometResultsPaginatedResultsQuery',
195
+ server_timestamps: 'true',
196
+ variables: JSON.stringify(variables),
197
+ doc_id: '26131941349797315',
198
+ };
199
+ const customHeader = {
200
+ 'x-fb-friendly-name': 'SearchCometResultsPaginatedResultsQuery',
201
+ 'x-fb-lsd': ctx.lsd || '',
202
+ 'x-asbd-id': '359341',
203
+ origin: 'https://www.facebook.com',
204
+ referer: `https://www.facebook.com/groups/search/groups_home?q=${encodeURIComponent(keyword)}&locale=${encodeURIComponent(locale)}`,
205
+ };
206
+ const res = await utils.post('https://www.facebook.com/api/graphql/', ctx.jar, form, ctx.globalOptions, ctx, customHeader);
207
+ const data = parseResponseBody(res.body);
208
+ if (data?.errors) {
209
+ throw new Error(JSON.stringify(data.errors));
210
+ }
211
+ const results = data?.data?.serpResponse?.results;
212
+ const edges = Array.isArray(results?.edges) ? results.edges : [];
213
+ const pageInfo = results?.page_info || {};
214
+ return {
215
+ groups: edges.map(mapSearchGroupEdge),
216
+ cursor: pageInfo.end_cursor || null,
217
+ hasNextPage: Boolean(pageInfo.has_next_page),
218
+ };
219
+ };
220
+ }
221
+ //# sourceMappingURL=searchGroups.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"searchGroups.js","sourceRoot":"","sources":["../../../../src/deltas/apis/users/searchGroups.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -88,8 +88,30 @@ export interface PostComment {
88
88
  }
89
89
 
90
90
  export interface GetPostCommentsOptions {
91
- story_fbid: string;
91
+ /** Numeric story_fbid (used with id to construct permalink.php URL) */
92
+ story_fbid?: string;
93
+ /** Facebook user/page ID (used with story_fbid) */
92
94
  id?: string;
95
+ /** Direct Facebook post URL (e.g. https://www.facebook.com/user/posts/pfbid...) */
96
+ url?: string;
97
+ /** Cursor for fetching next page of comments (from page_info.end_cursor) */
98
+ after?: string;
99
+ /** GraphQL feedback ID for pagination (from page_info.feedback_id) */
100
+ feedback_id?: string;
101
+ }
102
+
103
+ export interface PageInfo {
104
+ end_cursor: string | null;
105
+ has_next_page: boolean;
106
+ has_previous_page?: boolean;
107
+ start_cursor?: string | null;
108
+ /** GraphQL feedback ID needed for pagination queries */
109
+ feedback_id?: string;
110
+ }
111
+
112
+ export interface GetPostCommentsResult {
113
+ comments: PostComment[];
114
+ page_info: PageInfo | null;
93
115
  }
94
116
 
95
117
  export interface ShareResult {
@@ -374,6 +396,56 @@ export interface ThreadInfo {
374
396
  };
375
397
  }
376
398
 
399
+ export interface SearchGroupOptions {
400
+ limit?: number;
401
+ cursor?: string | null;
402
+ locale?: string;
403
+ }
404
+
405
+ export interface SearchGroupItem {
406
+ groupID: string | null;
407
+ name: string | null;
408
+ url: string | null;
409
+ profileUrl: string | null;
410
+ imageSrc: string | null;
411
+ summary: string | null;
412
+ privacy: string | null;
413
+ memberText: string | null;
414
+ memberCount: number | null;
415
+ joinState: string | null;
416
+ hasMembershipQuestions: boolean | null;
417
+ }
418
+
419
+ export interface SearchGroupResult {
420
+ groups: SearchGroupItem[];
421
+ cursor: string | null;
422
+ hasNextPage: boolean;
423
+ }
424
+
425
+ export interface GroupModule {
426
+ join(groupID: string): Promise<any>;
427
+ leave(groupID: string): Promise<any>;
428
+ getJoinedGroups(
429
+ cursor?: string | null,
430
+ count?: number,
431
+ ): Promise<{
432
+ groups: Array<{
433
+ id: string;
434
+ name: string;
435
+ imageUri: string;
436
+ url: string;
437
+ memberCount: string;
438
+ privacy: string;
439
+ }>;
440
+ endCursor: string | null;
441
+ hasNextPage: boolean;
442
+ }>;
443
+ searchGroup(
444
+ keyword: string,
445
+ options?: SearchGroupOptions,
446
+ ): Promise<SearchGroupResult>;
447
+ }
448
+
377
449
  export interface MessageObject {
378
450
  body?: string;
379
451
  attachment?: ReadStream[];
@@ -609,8 +681,9 @@ export interface API {
609
681
  ): Promise<DeletePostResult>;
610
682
  getComments(
611
683
  postID: string | GetPostCommentsOptions,
612
- callback?: Callback<PostComment[]>,
613
- ): Promise<PostComment[]>;
684
+ optionsOrCallback?: GetPostCommentsOptions | Callback<GetPostCommentsResult>,
685
+ callback?: Callback<GetPostCommentsResult>,
686
+ ): Promise<GetPostCommentsResult>;
614
687
  uploadPhoto(
615
688
  photoPath: string,
616
689
  callback?: Callback<UploadPhotoResult>,
@@ -852,6 +925,9 @@ export interface API {
852
925
  /** Add an external module to extend the API. */
853
926
  addExternalModule(moduleObj: Record<string, Function>): void;
854
927
 
928
+ /** Group-related API methods. */
929
+ group: GroupModule;
930
+
855
931
  /** Allow accessing dynamically loaded methods. */
856
932
  [key: string]: any;
857
933
  }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @namespace api.group
3
+ * @description A module for joining, leaving, and listing Facebook groups.
4
+ * @license Ex-it
5
+ */
6
+ export default function (defaultFuncs: any, api: any, ctx: any): {
7
+ /**
8
+ * Joins a Facebook group.
9
+ * @async
10
+ * @param {string} groupID The ID of the group to join.
11
+ * @returns {Promise<Object>} A promise that resolves to the API response data on success.
12
+ * @throws {Error} If the groupID is missing or the API request fails.
13
+ */
14
+ join: (groupID: string, inviteShortLinkKey?: string | null) => Promise<any>;
15
+ /**
16
+ * Leaves a Facebook group.
17
+ * @async
18
+ * @param {string} groupID The ID of the group to leave.
19
+ * @returns {Promise<Object>} A promise that resolves to the API response data on success.
20
+ * @throws {Error} If the groupID is missing or the API request fails.
21
+ */
22
+ leave: (groupID: string) => Promise<any>;
23
+ /**
24
+ * Invites friends to a Facebook group.
25
+ * @async
26
+ * @param {string} groupID The ID of the group to invite friends to.
27
+ * @param {string[]} userIDs Array of user IDs to invite.
28
+ * @returns {Promise<Object>} A promise that resolves to the API response data on success.
29
+ * @throws {Error} If the groupID or userIDs are missing or the API request fails.
30
+ */
31
+ inviteFriends: (groupID: string, userIDs: string[]) => Promise<any>;
32
+ /**
33
+ * Fetches the logged-in user's joined Facebook groups with cursor-based pagination.
34
+ *
35
+ * @param {string|null} [cursor=null] Pagination cursor from a previous result's `endCursor`.
36
+ * Pass `null` (or omit) for the first page.
37
+ * @param {number} [count=10] Number of groups to fetch per page (used for pagination requests).
38
+ * @returns {Promise<JoinedGroupsResult>} Groups list and pagination info.
39
+ *
40
+ * @example
41
+ * // Page 1
42
+ * const page1 = await api.group.getJoinedGroups();
43
+ * console.log(page1.groups); // Array of GroupEntry
44
+ * console.log(page1.endCursor); // cursor string for next page
45
+ *
46
+ * // Page 2+
47
+ * const page2 = await api.group.getJoinedGroups(page1.endCursor);
48
+ */
49
+ getJoinedGroups: (cursor?: string | null, count?: number) => Promise<{
50
+ groups: {
51
+ id: string;
52
+ name: string;
53
+ imageUri: string;
54
+ url: string;
55
+ memberCount: string;
56
+ privacy: string;
57
+ }[];
58
+ endCursor: string | null;
59
+ hasNextPage: boolean;
60
+ }>;
61
+ /**
62
+ * Search Facebook groups by keyword.
63
+ *
64
+ * @param {string} keyword Search keyword.
65
+ * @param {{ limit?: number; cursor?: string | null; locale?: string }} [options]
66
+ * @returns {Promise<{ groups: any[]; cursor: string | null; hasNextPage: boolean }>} Search result and pagination info.
67
+ */
68
+ searchGroup: (keyword: string, options?: {
69
+ limit?: number;
70
+ cursor?: string | null;
71
+ locale?: string;
72
+ }) => Promise<{
73
+ groups: any[];
74
+ cursor: string | null;
75
+ hasNextPage: boolean;
76
+ }>;
77
+ /**
78
+ * Alias for searchGroup.
79
+ * @see searchGroup
80
+ */
81
+ searchGroups: (keyword: string, options?: {
82
+ limit?: number;
83
+ cursor?: string | null;
84
+ locale?: string;
85
+ }) => Promise<{
86
+ groups: any[];
87
+ cursor: string | null;
88
+ hasNextPage: boolean;
89
+ }>;
90
+ };
@@ -21,7 +21,7 @@ export default function (defaultFuncs: any, api: any, ctx: any): {
21
21
  postID: any;
22
22
  data: any;
23
23
  }>;
24
- getComments: (postID: any, callback: any) => Promise<any>;
24
+ getComments: (postID: any, optionsOrCallback?: any, callback?: any) => Promise<any>;
25
25
  uploadPhoto: (photoPath: any, callback: any) => Promise<any>;
26
26
  uploadVideo: (videoPath: any, callback: any) => Promise<any>;
27
27
  };
@@ -0,0 +1,15 @@
1
+ type SearchGroupOptions = {
2
+ limit?: number;
3
+ cursor?: string | null;
4
+ locale?: string;
5
+ };
6
+ /**
7
+ * @ChoruOfficial
8
+ * @description Search Facebook groups by keyword using SearchCometResultsPaginatedResultsQuery.
9
+ */
10
+ export default function searchGroupModule(defaultFuncs: any, api: any, ctx: any): (keyword: string, options?: SearchGroupOptions) => Promise<{
11
+ groups: any[];
12
+ cursor: string | null;
13
+ hasNextPage: boolean;
14
+ }>;
15
+ export {};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @description A module for searching Facebook groups by keyword.
3
+ * Calls SearchCometResultsPaginatedResultsQuery via /api/graphql/.
4
+ * @param {Object} defaultFuncs The default functions provided by the API wrapper.
5
+ * @param {Object} api The full API object.
6
+ * @param {Object} ctx The context object containing the user's session state.
7
+ * @returns {Function} An async function that searches for groups by keyword.
8
+ */
9
+ export default function searchGroupsModule(defaultFuncs: any, api: any, ctx: any): (keyword: string, options?: {
10
+ limit?: number;
11
+ cursor?: string | null;
12
+ locale?: string;
13
+ }) => Promise<{
14
+ groups: any[];
15
+ cursor: string | null;
16
+ hasNextPage: boolean;
17
+ }>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bb-fca",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "BB-FCA is a powerful and user-friendly Facebook Chat API wrapper for Node.js, designed to simplify the process of creating chatbots and automating interactions on Facebook Messenger. With BB-FCA, developers can easily send messages, manage conversations, and interact with the Facebook Messenger platform using a simple and intuitive API.",
5
5
  "main": "dist/core/client.js",
6
6
  "types": "dist/index.d.ts",