@glagan/rettiwt-api 7.0.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.
Files changed (165) hide show
  1. package/.eslintrc.js +166 -0
  2. package/.gitattributes +3 -0
  3. package/.github/FUNDING.yml +4 -0
  4. package/.github/ISSUE_TEMPLATE/bug-report.yml +57 -0
  5. package/.github/ISSUE_TEMPLATE/feature-request.yml +20 -0
  6. package/.github/ISSUE_TEMPLATE/question.yml +15 -0
  7. package/.github/PULL_REQUEST_TEMPLATE.md +32 -0
  8. package/.github/workflows/ci.yml +32 -0
  9. package/.github/workflows/publish.yml +23 -0
  10. package/.nvmrc +1 -0
  11. package/.prettierignore +3 -0
  12. package/.prettierrc +13 -0
  13. package/LICENSE +21 -0
  14. package/README.md +566 -0
  15. package/dist/cli.js +43 -0
  16. package/eslint.config.mjs +17 -0
  17. package/package.json +50 -0
  18. package/src/Rettiwt.ts +97 -0
  19. package/src/cli.ts +48 -0
  20. package/src/collections/Extractors.ts +155 -0
  21. package/src/collections/Groups.ts +81 -0
  22. package/src/collections/Requests.ts +89 -0
  23. package/src/collections/Tweet.ts +17 -0
  24. package/src/commands/DirectMessage.ts +62 -0
  25. package/src/commands/List.ts +90 -0
  26. package/src/commands/Tweet.ts +437 -0
  27. package/src/commands/User.ts +367 -0
  28. package/src/enums/Api.ts +10 -0
  29. package/src/enums/Authentication.ts +10 -0
  30. package/src/enums/Data.ts +13 -0
  31. package/src/enums/Logging.ts +14 -0
  32. package/src/enums/Media.ts +10 -0
  33. package/src/enums/Notification.ts +12 -0
  34. package/src/enums/Resource.ts +69 -0
  35. package/src/enums/Tweet.ts +8 -0
  36. package/src/enums/raw/Analytics.ts +32 -0
  37. package/src/enums/raw/Media.ts +10 -0
  38. package/src/enums/raw/Notification.ts +11 -0
  39. package/src/enums/raw/Tweet.ts +20 -0
  40. package/src/helper/CliUtils.ts +17 -0
  41. package/src/helper/JsonUtils.ts +70 -0
  42. package/src/index.ts +128 -0
  43. package/src/models/RettiwtConfig.ts +101 -0
  44. package/src/models/args/FetchArgs.ts +169 -0
  45. package/src/models/args/PostArgs.ts +93 -0
  46. package/src/models/args/ProfileArgs.ts +68 -0
  47. package/src/models/auth/AuthCookie.ts +58 -0
  48. package/src/models/auth/AuthCredential.ts +83 -0
  49. package/src/models/data/Analytics.ts +97 -0
  50. package/src/models/data/BookmarkFolder.ts +73 -0
  51. package/src/models/data/Conversation.ts +344 -0
  52. package/src/models/data/CursoredData.ts +64 -0
  53. package/src/models/data/DirectMessage.ts +335 -0
  54. package/src/models/data/Inbox.ts +124 -0
  55. package/src/models/data/List.ts +113 -0
  56. package/src/models/data/Notification.ts +84 -0
  57. package/src/models/data/Tweet.ts +388 -0
  58. package/src/models/data/User.ts +187 -0
  59. package/src/models/errors/TwitterError.ts +65 -0
  60. package/src/models/params/Variables.ts +62 -0
  61. package/src/requests/DirectMessage.ts +229 -0
  62. package/src/requests/List.ts +203 -0
  63. package/src/requests/Media.ts +67 -0
  64. package/src/requests/Tweet.ts +607 -0
  65. package/src/requests/User.ts +1191 -0
  66. package/src/services/internal/AuthService.ts +115 -0
  67. package/src/services/internal/ErrorService.ts +41 -0
  68. package/src/services/internal/LogService.ts +34 -0
  69. package/src/services/public/DirectMessageService.ts +159 -0
  70. package/src/services/public/FetcherService.ts +366 -0
  71. package/src/services/public/ListService.ts +241 -0
  72. package/src/services/public/TweetService.ts +886 -0
  73. package/src/services/public/UserService.ts +1154 -0
  74. package/src/types/ErrorHandler.ts +13 -0
  75. package/src/types/Fetch.ts +3 -0
  76. package/src/types/RettiwtConfig.ts +48 -0
  77. package/src/types/args/FetchArgs.ts +233 -0
  78. package/src/types/args/PostArgs.ts +142 -0
  79. package/src/types/args/ProfileArgs.ts +33 -0
  80. package/src/types/auth/AuthCookie.ts +22 -0
  81. package/src/types/auth/AuthCredential.ts +28 -0
  82. package/src/types/auth/TransactionHeader.ts +8 -0
  83. package/src/types/data/Analytics.ts +58 -0
  84. package/src/types/data/BookmarkFolder.ts +12 -0
  85. package/src/types/data/Conversation.ts +44 -0
  86. package/src/types/data/CursoredData.ts +24 -0
  87. package/src/types/data/DirectMessage.ts +33 -0
  88. package/src/types/data/Inbox.ts +23 -0
  89. package/src/types/data/List.ts +33 -0
  90. package/src/types/data/Notification.ts +26 -0
  91. package/src/types/data/Tweet.ts +99 -0
  92. package/src/types/data/User.ts +54 -0
  93. package/src/types/errors/TwitterError.ts +37 -0
  94. package/src/types/params/Variables.ts +41 -0
  95. package/src/types/raw/base/Analytic.ts +32 -0
  96. package/src/types/raw/base/BookmarkFolder.ts +12 -0
  97. package/src/types/raw/base/Cursor.ts +13 -0
  98. package/src/types/raw/base/Error.ts +38 -0
  99. package/src/types/raw/base/LimitedVisibilityTweet.ts +40 -0
  100. package/src/types/raw/base/List.ts +50 -0
  101. package/src/types/raw/base/Media.ts +53 -0
  102. package/src/types/raw/base/Message.ts +22 -0
  103. package/src/types/raw/base/Notification.ts +66 -0
  104. package/src/types/raw/base/Space.ts +35 -0
  105. package/src/types/raw/base/Tweet.ts +139 -0
  106. package/src/types/raw/base/User.ts +182 -0
  107. package/src/types/raw/composite/DataResult.ts +8 -0
  108. package/src/types/raw/composite/TimelineList.ts +10 -0
  109. package/src/types/raw/composite/TimelineTweet.ts +14 -0
  110. package/src/types/raw/composite/TimelineUser.ts +13 -0
  111. package/src/types/raw/dm/Conversation.ts +59 -0
  112. package/src/types/raw/dm/InboxInitial.ts +155 -0
  113. package/src/types/raw/dm/InboxTimeline.ts +301 -0
  114. package/src/types/raw/dm/UserUpdates.ts +46 -0
  115. package/src/types/raw/generic/Response.ts +10 -0
  116. package/src/types/raw/list/AddMember.ts +175 -0
  117. package/src/types/raw/list/Details.ts +176 -0
  118. package/src/types/raw/list/Members.ts +154 -0
  119. package/src/types/raw/list/RemoveMember.ts +174 -0
  120. package/src/types/raw/list/Tweets.ts +2296 -0
  121. package/src/types/raw/media/FinalizeUpload.ts +20 -0
  122. package/src/types/raw/media/InitalizeUpload.ts +12 -0
  123. package/src/types/raw/media/LiveVideoStream.ts +21 -0
  124. package/src/types/raw/space/Details.ts +359 -0
  125. package/src/types/raw/tweet/Bookmark.ts +14 -0
  126. package/src/types/raw/tweet/Details.ts +210 -0
  127. package/src/types/raw/tweet/DetailsBulk.ts +338 -0
  128. package/src/types/raw/tweet/Like.ts +14 -0
  129. package/src/types/raw/tweet/Likers.ts +200 -0
  130. package/src/types/raw/tweet/Post.ts +150 -0
  131. package/src/types/raw/tweet/Replies.ts +539 -0
  132. package/src/types/raw/tweet/Retweet.ts +31 -0
  133. package/src/types/raw/tweet/Retweeters.ts +208 -0
  134. package/src/types/raw/tweet/Schedule.ts +18 -0
  135. package/src/types/raw/tweet/Search.ts +597 -0
  136. package/src/types/raw/tweet/Unbookmark.ts +14 -0
  137. package/src/types/raw/tweet/Unlike.ts +14 -0
  138. package/src/types/raw/tweet/Unpost.ts +20 -0
  139. package/src/types/raw/tweet/Unretweet.ts +31 -0
  140. package/src/types/raw/tweet/Unschedule.ts +14 -0
  141. package/src/types/raw/user/Affiliates.ts +179 -0
  142. package/src/types/raw/user/Analytics.ts +23 -0
  143. package/src/types/raw/user/BookmarkFolderTweets.ts +53 -0
  144. package/src/types/raw/user/BookmarkFolders.ts +41 -0
  145. package/src/types/raw/user/Bookmarks.ts +637 -0
  146. package/src/types/raw/user/Details.ts +185 -0
  147. package/src/types/raw/user/DetailsBulk.ts +104 -0
  148. package/src/types/raw/user/Follow.ts +280 -0
  149. package/src/types/raw/user/Followed.ts +1942 -0
  150. package/src/types/raw/user/Followers.ts +215 -0
  151. package/src/types/raw/user/Following.ts +215 -0
  152. package/src/types/raw/user/Highlights.ts +1287 -0
  153. package/src/types/raw/user/Likes.ts +1254 -0
  154. package/src/types/raw/user/Lists.ts +378 -0
  155. package/src/types/raw/user/Media.ts +1738 -0
  156. package/src/types/raw/user/Notifications.ts +499 -0
  157. package/src/types/raw/user/ProfileUpdate.ts +80 -0
  158. package/src/types/raw/user/Recommended.ts +2319 -0
  159. package/src/types/raw/user/Scheduled.ts +37 -0
  160. package/src/types/raw/user/Search.ts +230 -0
  161. package/src/types/raw/user/Subscriptions.ts +176 -0
  162. package/src/types/raw/user/Tweets.ts +1254 -0
  163. package/src/types/raw/user/TweetsAndReplies.ts +1254 -0
  164. package/src/types/raw/user/Unfollow.ts +280 -0
  165. package/tsconfig.json +97 -0
@@ -0,0 +1,1191 @@
1
+ import qs from 'querystring';
2
+
3
+ import { RawAnalyticsGranularity, RawAnalyticsMetric } from '../enums/raw/Analytics';
4
+ import { IProfileUpdateOptions } from '../types/args/ProfileArgs';
5
+ import { FetchConfig } from '../types/Fetch';
6
+
7
+ /**
8
+ * Collection of requests related to users.
9
+ *
10
+ * @public
11
+ */
12
+ export class UserRequests {
13
+ /**
14
+ * @param id - The id of the user whose affiliates are to be fetched.
15
+ * @param count - The number of affiliates to fetch. Only works as a lower limit when used with a cursor.
16
+ * @param cursor - The cursor to the batch of affiliates to fetch.
17
+ */
18
+ public static affiliates(id: string, count?: number, cursor?: string): FetchConfig {
19
+ return {
20
+ method: 'get',
21
+ url: 'https://x.com/i/api/graphql/KFaAofDlKP7bnzskNWmjwA/UserBusinessProfileTeamTimeline',
22
+ params: {
23
+ /* eslint-disable @typescript-eslint/naming-convention */
24
+ variables: JSON.stringify({
25
+ userId: id,
26
+ count: count,
27
+ cursor: cursor,
28
+ teamName: 'NotAssigned',
29
+ includePromotedContent: false,
30
+ withClientEventToken: false,
31
+ withVoice: false,
32
+ }),
33
+ features: JSON.stringify({
34
+ rweb_video_screen_enabled: false,
35
+ profile_label_improvements_pcf_label_in_post_enabled: true,
36
+ responsive_web_profile_redirect_enabled: false,
37
+ rweb_tipjar_consumption_enabled: true,
38
+ verified_phone_label_enabled: true,
39
+ creator_subscriptions_tweet_preview_api_enabled: true,
40
+ responsive_web_graphql_timeline_navigation_enabled: true,
41
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
42
+ premium_content_api_read_enabled: false,
43
+ communities_web_enable_tweet_community_results_fetch: true,
44
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
45
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
46
+ responsive_web_grok_analyze_post_followups_enabled: true,
47
+ responsive_web_jetfuel_frame: true,
48
+ responsive_web_grok_share_attachment_enabled: true,
49
+ articles_preview_enabled: true,
50
+ responsive_web_edit_tweet_api_enabled: true,
51
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
52
+ view_counts_everywhere_api_enabled: true,
53
+ longform_notetweets_consumption_enabled: true,
54
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
55
+ tweet_awards_web_tipping_enabled: false,
56
+ responsive_web_grok_show_grok_translated_post: false,
57
+ responsive_web_grok_analysis_button_from_backend: true,
58
+ creator_subscriptions_quote_tweet_preview_enabled: false,
59
+ freedom_of_speech_not_reach_fetch_enabled: true,
60
+ standardized_nudges_misinfo: true,
61
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
62
+ longform_notetweets_rich_text_read_enabled: true,
63
+ longform_notetweets_inline_media_enabled: true,
64
+ responsive_web_grok_image_annotation_enabled: true,
65
+ responsive_web_grok_imagine_annotation_enabled: true,
66
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
67
+ responsive_web_enhance_cards_enabled: false,
68
+ }),
69
+ /* eslint-enable @typescript-eslint/naming-convention */
70
+ },
71
+ };
72
+ }
73
+
74
+ /**
75
+ * @param fromTime - The start time of the analytic data to be fetched.
76
+ * @param toTime - The end time of the analytic data to be fetched.
77
+ * @param granularity - The granularity of the analytic data to be fetched.
78
+ * @param requestedMetrics - The metrics to be fetched.
79
+ * @param showVerifiedFollowers - Whether to show verified followers in the analytics.
80
+ */
81
+ public static analytics(
82
+ fromTime: Date,
83
+ toTime: Date,
84
+ granularity: RawAnalyticsGranularity,
85
+ requestedMetrics: RawAnalyticsMetric[],
86
+ showVerifiedFollowers: boolean,
87
+ ): FetchConfig {
88
+ console.log(
89
+ `Fetching analytics from ${fromTime?.toString()} to ${toTime?.toString()} with granularity ${granularity} and metrics ${requestedMetrics.join(', ')}`,
90
+ );
91
+ return {
92
+ method: 'get',
93
+ url: 'https://x.com/i/api/graphql/LwtiA7urqM6eDeBheAFi5w/AccountOverviewQuery',
94
+ params: {
95
+ variables: JSON.stringify({
96
+ /* eslint-disable @typescript-eslint/naming-convention */
97
+ from_time: fromTime,
98
+ to_time: toTime,
99
+ granularity: granularity,
100
+ requested_metrics: requestedMetrics,
101
+ show_verified_followers: showVerifiedFollowers,
102
+ /* eslint-enable @typescript-eslint/naming-convention */
103
+ }),
104
+ },
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Fetches tweets from a specific bookmark folder.
110
+ *
111
+ * @param folderId - The ID of the bookmark folder.
112
+ * @param count - The number of tweets to fetch.
113
+ * @param cursor - The cursor to the batch of tweets to fetch.
114
+ */
115
+ public static bookmarkFolderTweets(folderId: string, count?: number, cursor?: string): FetchConfig {
116
+ return {
117
+ method: 'get',
118
+ url: 'https://x.com/i/api/graphql/KJIQpsvxrTfRIlbaRIySHQ/BookmarkFolderTimeline',
119
+ params: {
120
+ /* eslint-disable @typescript-eslint/naming-convention */
121
+ variables: JSON.stringify({
122
+ bookmark_collection_id: folderId,
123
+ count: count,
124
+ cursor: cursor,
125
+ includePromotedContent: true,
126
+ }),
127
+ features: JSON.stringify({
128
+ rweb_video_screen_enabled: false,
129
+ profile_label_improvements_pcf_label_in_post_enabled: true,
130
+ responsive_web_profile_redirect_enabled: false,
131
+ rweb_tipjar_consumption_enabled: true,
132
+ verified_phone_label_enabled: true,
133
+ creator_subscriptions_tweet_preview_api_enabled: true,
134
+ responsive_web_graphql_timeline_navigation_enabled: true,
135
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
136
+ premium_content_api_read_enabled: false,
137
+ communities_web_enable_tweet_community_results_fetch: true,
138
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
139
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
140
+ responsive_web_grok_analyze_post_followups_enabled: true,
141
+ responsive_web_jetfuel_frame: true,
142
+ responsive_web_grok_share_attachment_enabled: true,
143
+ articles_preview_enabled: true,
144
+ responsive_web_edit_tweet_api_enabled: true,
145
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
146
+ view_counts_everywhere_api_enabled: true,
147
+ longform_notetweets_consumption_enabled: true,
148
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
149
+ tweet_awards_web_tipping_enabled: false,
150
+ responsive_web_grok_show_grok_translated_post: false,
151
+ responsive_web_grok_analysis_button_from_backend: true,
152
+ creator_subscriptions_quote_tweet_preview_enabled: false,
153
+ freedom_of_speech_not_reach_fetch_enabled: true,
154
+ responsive_web_grok_imagine_annotation_enabled: false,
155
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
156
+ standardized_nudges_misinfo: true,
157
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
158
+ longform_notetweets_rich_text_read_enabled: true,
159
+ longform_notetweets_inline_media_enabled: true,
160
+ responsive_web_grok_image_annotation_enabled: true,
161
+ responsive_web_enhance_cards_enabled: false,
162
+ }),
163
+ /* eslint-enable @typescript-eslint/naming-convention */
164
+ },
165
+ };
166
+ }
167
+
168
+ /**
169
+ * Fetches the list of bookmark folders for the logged-in user.
170
+ *
171
+ * @param cursor - The cursor to the batch of bookmark folders to fetch.
172
+ */
173
+ public static bookmarkFolders(cursor?: string): FetchConfig {
174
+ return {
175
+ method: 'get',
176
+ url: 'https://x.com/i/api/graphql/i78YDd0Tza-dV4SYs58kRg/BookmarkFoldersSlice',
177
+ params: {
178
+ /* eslint-disable @typescript-eslint/naming-convention */
179
+ variables: JSON.stringify({
180
+ cursor: cursor,
181
+ }),
182
+ features: JSON.stringify({
183
+ rweb_video_screen_enabled: false,
184
+ profile_label_improvements_pcf_label_in_post_enabled: true,
185
+ rweb_tipjar_consumption_enabled: true,
186
+ verified_phone_label_enabled: true,
187
+ creator_subscriptions_tweet_preview_api_enabled: true,
188
+ responsive_web_graphql_timeline_navigation_enabled: true,
189
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
190
+ premium_content_api_read_enabled: false,
191
+ communities_web_enable_tweet_community_results_fetch: true,
192
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
193
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
194
+ responsive_web_grok_analyze_post_followups_enabled: true,
195
+ responsive_web_jetfuel_frame: false,
196
+ responsive_web_grok_share_attachment_enabled: true,
197
+ articles_preview_enabled: true,
198
+ responsive_web_edit_tweet_api_enabled: true,
199
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
200
+ view_counts_everywhere_api_enabled: true,
201
+ longform_notetweets_consumption_enabled: true,
202
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
203
+ tweet_awards_web_tipping_enabled: false,
204
+ responsive_web_grok_show_grok_translated_post: false,
205
+ responsive_web_grok_analysis_button_from_backend: true,
206
+ creator_subscriptions_quote_tweet_preview_enabled: false,
207
+ freedom_of_speech_not_reach_fetch_enabled: true,
208
+ responsive_web_grok_imagine_annotation_enabled: false,
209
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
210
+ responsive_web_profile_redirect_enabled: false,
211
+ standardized_nudges_misinfo: true,
212
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
213
+ longform_notetweets_rich_text_read_enabled: true,
214
+ longform_notetweets_inline_media_enabled: true,
215
+ responsive_web_grok_image_annotation_enabled: true,
216
+ responsive_web_enhance_cards_enabled: false,
217
+ }),
218
+ /* eslint-enable @typescript-eslint/naming-convention */
219
+ },
220
+ };
221
+ }
222
+
223
+ /**
224
+ * @param count - The number of bookmarks to fetch.
225
+ * @param cursor - The cursor to the batch of bookmarks to fetch.
226
+ */
227
+ public static bookmarks(count?: number, cursor?: string): FetchConfig {
228
+ return {
229
+ method: 'get',
230
+ url: 'https://x.com/i/api/graphql/-LGfdImKeQz0xS_jjUwzlA/Bookmarks',
231
+ params: {
232
+ /* eslint-disable @typescript-eslint/naming-convention */
233
+ variables: JSON.stringify({
234
+ count: count,
235
+ cursor: cursor,
236
+ includePromotedContent: false,
237
+ }),
238
+ features: JSON.stringify({
239
+ rweb_video_screen_enabled: false,
240
+ profile_label_improvements_pcf_label_in_post_enabled: true,
241
+ rweb_tipjar_consumption_enabled: true,
242
+ verified_phone_label_enabled: true,
243
+ creator_subscriptions_tweet_preview_api_enabled: true,
244
+ responsive_web_graphql_timeline_navigation_enabled: true,
245
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
246
+ premium_content_api_read_enabled: false,
247
+ communities_web_enable_tweet_community_results_fetch: true,
248
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
249
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
250
+ responsive_web_grok_analyze_post_followups_enabled: true,
251
+ responsive_web_jetfuel_frame: false,
252
+ responsive_web_grok_share_attachment_enabled: true,
253
+ articles_preview_enabled: true,
254
+ responsive_web_edit_tweet_api_enabled: true,
255
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
256
+ view_counts_everywhere_api_enabled: true,
257
+ longform_notetweets_consumption_enabled: true,
258
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
259
+ tweet_awards_web_tipping_enabled: false,
260
+ responsive_web_grok_show_grok_translated_post: false,
261
+ responsive_web_grok_analysis_button_from_backend: true,
262
+ creator_subscriptions_quote_tweet_preview_enabled: false,
263
+ freedom_of_speech_not_reach_fetch_enabled: true,
264
+ responsive_web_grok_imagine_annotation_enabled: false,
265
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
266
+ responsive_web_profile_redirect_enabled: false,
267
+ standardized_nudges_misinfo: true,
268
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
269
+ longform_notetweets_rich_text_read_enabled: true,
270
+ longform_notetweets_inline_media_enabled: true,
271
+ responsive_web_grok_image_annotation_enabled: true,
272
+ responsive_web_enhance_cards_enabled: false,
273
+ }),
274
+ /* eslint-enable @typescript-eslint/naming-convention */
275
+ },
276
+ };
277
+ }
278
+
279
+ /**
280
+ * @param ids - The IDs of the users whose details are to be fetched.
281
+ */
282
+ public static bulkDetailsByIds(ids: string[]): FetchConfig {
283
+ return {
284
+ method: 'get',
285
+ url: 'https://x.com/i/api/graphql/xavgLWWbFH8wm_8MQN8plQ/UsersByRestIds',
286
+ params: {
287
+ /* eslint-disable @typescript-eslint/naming-convention */
288
+ variables: JSON.stringify({ userIds: ids }),
289
+ features: JSON.stringify({
290
+ hidden_profile_likes_enabled: false,
291
+ hidden_profile_subscriptions_enabled: false,
292
+ responsive_web_graphql_exclude_directive_enabled: true,
293
+ verified_phone_label_enabled: true,
294
+ subscriptions_verification_info_verified_since_enabled: true,
295
+ highlights_tweets_tab_ui_enabled: true,
296
+ creator_subscriptions_tweet_preview_api_enabled: true,
297
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
298
+ responsive_web_graphql_timeline_navigation_enabled: true,
299
+ profile_label_improvements_pcf_label_in_post_enabled: false,
300
+ rweb_tipjar_consumption_enabled: false,
301
+ responsive_web_profile_redirect_enabled: false,
302
+ }),
303
+ /* eslint-enable @typescript-eslint/naming-convention */
304
+ },
305
+ };
306
+ }
307
+
308
+ /**
309
+ * @param id - The id of the user whose details are to be fetched.
310
+ */
311
+ public static detailsById(id: string): FetchConfig {
312
+ return {
313
+ method: 'get',
314
+ url: 'https://x.com/i/api/graphql/Bbaot8ySMtJD7K2t01gW7A/UserByRestId',
315
+ params: {
316
+ /* eslint-disable @typescript-eslint/naming-convention */
317
+ variables: JSON.stringify({ userId: id, withSafetyModeUserFields: true }),
318
+ features: JSON.stringify({
319
+ hidden_profile_subscriptions_enabled: true,
320
+ profile_label_improvements_pcf_label_in_post_enabled: true,
321
+ rweb_tipjar_consumption_enabled: true,
322
+ verified_phone_label_enabled: true,
323
+ highlights_tweets_tab_ui_enabled: true,
324
+ responsive_web_twitter_article_notes_tab_enabled: true,
325
+ subscriptions_feature_can_gift_premium: true,
326
+ creator_subscriptions_tweet_preview_api_enabled: true,
327
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: true,
328
+ responsive_web_graphql_timeline_navigation_enabled: true,
329
+ responsive_web_profile_redirect_enabled: false,
330
+ }),
331
+ /* eslint-enable @typescript-eslint/naming-convention */
332
+ },
333
+ };
334
+ }
335
+
336
+ /**
337
+ * @param userName - The username of the user whose details are to be fetched.
338
+ */
339
+ public static detailsByUsername(userName: string): FetchConfig {
340
+ return {
341
+ method: 'get',
342
+ url: 'https://x.com/i/api/graphql/-oaLodhGbbnzJBACb1kk2Q/UserByScreenName',
343
+ params: {
344
+ /* eslint-disable @typescript-eslint/naming-convention */
345
+ variables: JSON.stringify({ screen_name: userName, withGrokTranslatedBio: false }),
346
+ features: JSON.stringify({
347
+ hidden_profile_subscriptions_enabled: true,
348
+ profile_label_improvements_pcf_label_in_post_enabled: true,
349
+ responsive_web_profile_redirect_enabled: false,
350
+ rweb_tipjar_consumption_enabled: true,
351
+ verified_phone_label_enabled: true,
352
+ subscriptions_verification_info_is_identity_verified_enabled: true,
353
+ subscriptions_verification_info_verified_since_enabled: true,
354
+ highlights_tweets_tab_ui_enabled: true,
355
+ responsive_web_twitter_article_notes_tab_enabled: true,
356
+ subscriptions_feature_can_gift_premium: true,
357
+ creator_subscriptions_tweet_preview_api_enabled: true,
358
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
359
+ responsive_web_graphql_timeline_navigation_enabled: true,
360
+ }),
361
+ fieldToggles: JSON.stringify({ withAuxiliaryUserLabels: true }),
362
+ /* eslint-enable @typescript-eslint/naming-convention */
363
+ },
364
+ };
365
+ }
366
+
367
+ /**
368
+ * @param id - The id of the user to follow.
369
+ */
370
+ public static follow(id: string): FetchConfig {
371
+ return {
372
+ method: 'post',
373
+ url: 'https://x.com/i/api/1.1/friendships/create.json',
374
+ body: qs.stringify({
375
+ /* eslint-disable @typescript-eslint/naming-convention */
376
+ user_id: id,
377
+ /* eslint-enable @typescript-eslint/naming-convention */
378
+ }),
379
+ };
380
+ }
381
+
382
+ /**
383
+ * @param count - The number of timeline items to fetch. Only works as a lower limit when used with a cursor.
384
+ * @param cursor - The cursor to the batch of followed timeline items to fetch.
385
+ */
386
+ public static followed(count?: number, cursor?: string): FetchConfig {
387
+ return {
388
+ method: 'get',
389
+ url: 'https://x.com/i/api/graphql/_qO7FJzShSKYWi9gtboE6A/HomeLatestTimeline',
390
+ params: {
391
+ /* eslint-disable @typescript-eslint/naming-convention */
392
+ variables: JSON.stringify({
393
+ count: count,
394
+ cursor: cursor,
395
+ includePromotedContent: false,
396
+ latestControlAvailable: true,
397
+ withCommunity: false,
398
+ }),
399
+ features: JSON.stringify({
400
+ rweb_video_screen_enabled: false,
401
+ profile_label_improvements_pcf_label_in_post_enabled: true,
402
+ responsive_web_profile_redirect_enabled: false,
403
+ rweb_tipjar_consumption_enabled: true,
404
+ verified_phone_label_enabled: true,
405
+ creator_subscriptions_tweet_preview_api_enabled: true,
406
+ responsive_web_graphql_timeline_navigation_enabled: true,
407
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
408
+ premium_content_api_read_enabled: false,
409
+ communities_web_enable_tweet_community_results_fetch: true,
410
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
411
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
412
+ responsive_web_grok_analyze_post_followups_enabled: true,
413
+ responsive_web_jetfuel_frame: true,
414
+ responsive_web_grok_share_attachment_enabled: true,
415
+ articles_preview_enabled: true,
416
+ responsive_web_edit_tweet_api_enabled: true,
417
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
418
+ view_counts_everywhere_api_enabled: true,
419
+ longform_notetweets_consumption_enabled: true,
420
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
421
+ tweet_awards_web_tipping_enabled: false,
422
+ responsive_web_grok_show_grok_translated_post: false,
423
+ responsive_web_grok_analysis_button_from_backend: true,
424
+ creator_subscriptions_quote_tweet_preview_enabled: false,
425
+ freedom_of_speech_not_reach_fetch_enabled: true,
426
+ standardized_nudges_misinfo: true,
427
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
428
+ longform_notetweets_rich_text_read_enabled: true,
429
+ longform_notetweets_inline_media_enabled: true,
430
+ responsive_web_grok_image_annotation_enabled: true,
431
+ responsive_web_grok_imagine_annotation_enabled: true,
432
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
433
+ responsive_web_enhance_cards_enabled: false,
434
+ }),
435
+ /* eslint-enable @typescript-eslint/naming-convention */
436
+ },
437
+ };
438
+ }
439
+
440
+ /**
441
+ * @param id - The id of the user whose followers are to be fetched.
442
+ * @param count - The number of followers to fetch. Only works as a lower limit when used with a cursor.
443
+ * @param cursor - The cursor to the batch of followers to fetch.
444
+ */
445
+ public static followers(id: string, count?: number, cursor?: string): FetchConfig {
446
+ return {
447
+ method: 'get',
448
+ url: 'https://x.com/i/api/graphql/kuFUYP9eV1FPoEy4N-pi7w/Followers',
449
+ params: {
450
+ /* eslint-disable @typescript-eslint/naming-convention */
451
+ variables: JSON.stringify({
452
+ userId: id,
453
+ count: count,
454
+ cursor: cursor,
455
+ includePromotedContent: false,
456
+ withGrokTranslatedBio: false,
457
+ }),
458
+ features: JSON.stringify({
459
+ rweb_video_screen_enabled: false,
460
+ profile_label_improvements_pcf_label_in_post_enabled: true,
461
+ responsive_web_profile_redirect_enabled: false,
462
+ rweb_tipjar_consumption_enabled: true,
463
+ verified_phone_label_enabled: true,
464
+ creator_subscriptions_tweet_preview_api_enabled: true,
465
+ responsive_web_graphql_timeline_navigation_enabled: true,
466
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
467
+ premium_content_api_read_enabled: false,
468
+ communities_web_enable_tweet_community_results_fetch: true,
469
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
470
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
471
+ responsive_web_grok_analyze_post_followups_enabled: true,
472
+ responsive_web_jetfuel_frame: true,
473
+ responsive_web_grok_share_attachment_enabled: true,
474
+ articles_preview_enabled: true,
475
+ responsive_web_edit_tweet_api_enabled: true,
476
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
477
+ view_counts_everywhere_api_enabled: true,
478
+ longform_notetweets_consumption_enabled: true,
479
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
480
+ tweet_awards_web_tipping_enabled: false,
481
+ responsive_web_grok_show_grok_translated_post: false,
482
+ responsive_web_grok_analysis_button_from_backend: true,
483
+ creator_subscriptions_quote_tweet_preview_enabled: false,
484
+ freedom_of_speech_not_reach_fetch_enabled: true,
485
+ standardized_nudges_misinfo: true,
486
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
487
+ longform_notetweets_rich_text_read_enabled: true,
488
+ longform_notetweets_inline_media_enabled: true,
489
+ responsive_web_grok_image_annotation_enabled: true,
490
+ responsive_web_grok_imagine_annotation_enabled: true,
491
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
492
+ responsive_web_enhance_cards_enabled: false,
493
+ }),
494
+ /* eslint-enable @typescript-eslint/naming-convention */
495
+ },
496
+ };
497
+ }
498
+
499
+ /**
500
+ * @param id - The id of the user whose followings are to be fetched.
501
+ * @param count - The number of followings to fetch. Only works as a lower limit when used with a cursor.
502
+ * @param cursor - The cursor to the batch of followings to fetch.
503
+ */
504
+ public static following(id: string, count?: number, cursor?: string): FetchConfig {
505
+ return {
506
+ method: 'get',
507
+ url: 'https://x.com/i/api/graphql/C1qZ6bs-L3oc_TKSZyxkXQ/Following',
508
+ params: {
509
+ /* eslint-disable @typescript-eslint/naming-convention */
510
+ variables: JSON.stringify({
511
+ userId: id,
512
+ count: count,
513
+ cursor: cursor,
514
+ includePromotedContent: false,
515
+ }),
516
+ features: JSON.stringify({
517
+ rweb_video_screen_enabled: false,
518
+ profile_label_improvements_pcf_label_in_post_enabled: true,
519
+ rweb_tipjar_consumption_enabled: true,
520
+ verified_phone_label_enabled: true,
521
+ creator_subscriptions_tweet_preview_api_enabled: true,
522
+ responsive_web_graphql_timeline_navigation_enabled: true,
523
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
524
+ premium_content_api_read_enabled: false,
525
+ communities_web_enable_tweet_community_results_fetch: true,
526
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
527
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
528
+ responsive_web_grok_analyze_post_followups_enabled: true,
529
+ responsive_web_jetfuel_frame: false,
530
+ responsive_web_grok_share_attachment_enabled: true,
531
+ articles_preview_enabled: true,
532
+ responsive_web_edit_tweet_api_enabled: true,
533
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
534
+ view_counts_everywhere_api_enabled: true,
535
+ longform_notetweets_consumption_enabled: true,
536
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
537
+ tweet_awards_web_tipping_enabled: false,
538
+ responsive_web_grok_show_grok_translated_post: false,
539
+ responsive_web_grok_analysis_button_from_backend: true,
540
+ creator_subscriptions_quote_tweet_preview_enabled: false,
541
+ freedom_of_speech_not_reach_fetch_enabled: true,
542
+ standardized_nudges_misinfo: true,
543
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
544
+ longform_notetweets_rich_text_read_enabled: true,
545
+ longform_notetweets_inline_media_enabled: true,
546
+ responsive_web_grok_image_annotation_enabled: true,
547
+ responsive_web_enhance_cards_enabled: false,
548
+ }),
549
+ /* eslint-enable @typescript-eslint/naming-convention */
550
+ },
551
+ };
552
+ }
553
+
554
+ /**
555
+ * @param id - The id of the user whose highlights are to be fetched.
556
+ * @param count - The number of highlights to fetch. Only works as a lower limit when used with a cursor.
557
+ * @param cursor - The cursor to the batch of highlights to fetch.
558
+ */
559
+ public static highlights(id: string, count?: number, cursor?: string): FetchConfig {
560
+ return {
561
+ method: 'get',
562
+ url: 'https://x.com/i/api/graphql/kzKWdUA6Y1LCqlvaVILZwQ/UserHighlightsTweets',
563
+ params: {
564
+ /* eslint-disable @typescript-eslint/naming-convention */
565
+ variables: JSON.stringify({
566
+ userId: id,
567
+ count: count,
568
+ cursor: cursor,
569
+ includePromotedContent: false,
570
+ withVoice: false,
571
+ }),
572
+ features: JSON.stringify({
573
+ rweb_video_screen_enabled: false,
574
+ profile_label_improvements_pcf_label_in_post_enabled: true,
575
+ responsive_web_profile_redirect_enabled: false,
576
+ rweb_tipjar_consumption_enabled: true,
577
+ verified_phone_label_enabled: true,
578
+ creator_subscriptions_tweet_preview_api_enabled: true,
579
+ responsive_web_graphql_timeline_navigation_enabled: true,
580
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
581
+ premium_content_api_read_enabled: false,
582
+ communities_web_enable_tweet_community_results_fetch: true,
583
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
584
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
585
+ responsive_web_grok_analyze_post_followups_enabled: true,
586
+ responsive_web_jetfuel_frame: true,
587
+ responsive_web_grok_share_attachment_enabled: true,
588
+ articles_preview_enabled: true,
589
+ responsive_web_edit_tweet_api_enabled: true,
590
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
591
+ view_counts_everywhere_api_enabled: true,
592
+ longform_notetweets_consumption_enabled: true,
593
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
594
+ tweet_awards_web_tipping_enabled: false,
595
+ responsive_web_grok_show_grok_translated_post: false,
596
+ responsive_web_grok_analysis_button_from_backend: true,
597
+ creator_subscriptions_quote_tweet_preview_enabled: false,
598
+ freedom_of_speech_not_reach_fetch_enabled: true,
599
+ standardized_nudges_misinfo: true,
600
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
601
+ longform_notetweets_rich_text_read_enabled: true,
602
+ longform_notetweets_inline_media_enabled: true,
603
+ responsive_web_grok_image_annotation_enabled: true,
604
+ responsive_web_grok_imagine_annotation_enabled: true,
605
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
606
+ responsive_web_enhance_cards_enabled: false,
607
+ }),
608
+ fieldToggles: { withArticlePlainText: false },
609
+ /* eslint-enable @typescript-eslint/naming-convention */
610
+ },
611
+ };
612
+ }
613
+
614
+ /**
615
+ * @param id - The id of the user whose likes are to be fetched.
616
+ * @param count - The number of likes to fetch. Only works as a lower limit when used with a cursor.
617
+ * @param cursor - The cursor to the batch of likes to fetch.
618
+ */
619
+ public static likes(id: string, count?: number, cursor?: string): FetchConfig {
620
+ return {
621
+ method: 'get',
622
+ url: 'https://x.com/i/api/graphql/JR2gceKucIKcVNB_9JkhsA/Likes',
623
+ params: {
624
+ /* eslint-disable @typescript-eslint/naming-convention */
625
+ variables: JSON.stringify({
626
+ userId: id,
627
+ count: count,
628
+ cursor: cursor,
629
+ includePromotedContent: false,
630
+ withClientEventToken: false,
631
+ withBirdwatchNotes: false,
632
+ withVoice: false,
633
+ withV2Timeline: false,
634
+ }),
635
+ features: JSON.stringify({
636
+ rweb_video_screen_enabled: false,
637
+ profile_label_improvements_pcf_label_in_post_enabled: true,
638
+ responsive_web_profile_redirect_enabled: false,
639
+ rweb_tipjar_consumption_enabled: true,
640
+ verified_phone_label_enabled: true,
641
+ creator_subscriptions_tweet_preview_api_enabled: true,
642
+ responsive_web_graphql_timeline_navigation_enabled: true,
643
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
644
+ premium_content_api_read_enabled: false,
645
+ communities_web_enable_tweet_community_results_fetch: true,
646
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
647
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
648
+ responsive_web_grok_analyze_post_followups_enabled: true,
649
+ responsive_web_jetfuel_frame: true,
650
+ responsive_web_grok_share_attachment_enabled: true,
651
+ articles_preview_enabled: true,
652
+ responsive_web_edit_tweet_api_enabled: true,
653
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
654
+ view_counts_everywhere_api_enabled: true,
655
+ longform_notetweets_consumption_enabled: true,
656
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
657
+ tweet_awards_web_tipping_enabled: false,
658
+ responsive_web_grok_show_grok_translated_post: false,
659
+ responsive_web_grok_analysis_button_from_backend: true,
660
+ creator_subscriptions_quote_tweet_preview_enabled: false,
661
+ freedom_of_speech_not_reach_fetch_enabled: true,
662
+ standardized_nudges_misinfo: true,
663
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
664
+ longform_notetweets_rich_text_read_enabled: true,
665
+ longform_notetweets_inline_media_enabled: true,
666
+ responsive_web_grok_image_annotation_enabled: true,
667
+ responsive_web_grok_imagine_annotation_enabled: true,
668
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
669
+ responsive_web_enhance_cards_enabled: false,
670
+ }),
671
+ fieldToggles: { withArticlePlainText: false },
672
+ /* eslint-enable @typescript-eslint/naming-convention */
673
+ },
674
+ };
675
+ }
676
+
677
+ /**
678
+ * @param id - The id of the user whose lists are to be fetched.
679
+ * @param count - The number of lists to fetch. Only works as a lower limit when used with a cursor.
680
+ * @param cursor - The cursor to the batch of lists to fetch.
681
+ */
682
+ public static lists(id: string, count?: number, cursor?: string): FetchConfig {
683
+ return {
684
+ method: 'get',
685
+ url: 'https://x.com/i/api/graphql/9mQl9vR31wjodBP9b7_wyQ/ListsManagementPageTimeline',
686
+ params: {
687
+ /* eslint-disable @typescript-eslint/naming-convention */
688
+ variables: JSON.stringify({ count: 100, cursor: cursor }),
689
+ features: JSON.stringify({
690
+ rweb_video_screen_enabled: false,
691
+ profile_label_improvements_pcf_label_in_post_enabled: true,
692
+ responsive_web_profile_redirect_enabled: false,
693
+ rweb_tipjar_consumption_enabled: true,
694
+ verified_phone_label_enabled: true,
695
+ creator_subscriptions_tweet_preview_api_enabled: true,
696
+ responsive_web_graphql_timeline_navigation_enabled: true,
697
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
698
+ premium_content_api_read_enabled: false,
699
+ communities_web_enable_tweet_community_results_fetch: true,
700
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
701
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
702
+ responsive_web_grok_analyze_post_followups_enabled: true,
703
+ responsive_web_jetfuel_frame: true,
704
+ responsive_web_grok_share_attachment_enabled: true,
705
+ articles_preview_enabled: true,
706
+ responsive_web_edit_tweet_api_enabled: true,
707
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
708
+ view_counts_everywhere_api_enabled: true,
709
+ longform_notetweets_consumption_enabled: true,
710
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
711
+ tweet_awards_web_tipping_enabled: false,
712
+ responsive_web_grok_show_grok_translated_post: false,
713
+ responsive_web_grok_analysis_button_from_backend: true,
714
+ creator_subscriptions_quote_tweet_preview_enabled: false,
715
+ freedom_of_speech_not_reach_fetch_enabled: true,
716
+ standardized_nudges_misinfo: true,
717
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
718
+ longform_notetweets_rich_text_read_enabled: true,
719
+ longform_notetweets_inline_media_enabled: true,
720
+ responsive_web_grok_image_annotation_enabled: true,
721
+ responsive_web_grok_imagine_annotation_enabled: true,
722
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
723
+ responsive_web_enhance_cards_enabled: false,
724
+ }),
725
+ fieldToggles: { withArticlePlainText: false },
726
+ /* eslint-enable @typescript-eslint/naming-convention */
727
+ },
728
+ };
729
+ }
730
+
731
+ /**
732
+ * @param id - The id of the user whose media is to be fetched.
733
+ * @param count - The number of media to fetch. Only works as a lower limit when used with a cursor.
734
+ * @param cursor - The cursor to the batch of media to fetch.
735
+ */
736
+ public static media(id: string, count?: number, cursor?: string): FetchConfig {
737
+ return {
738
+ method: 'get',
739
+ url: 'https://x.com/i/api/graphql/MMnr49cP_nldzCTfeVDRtA/UserMedia',
740
+ params: {
741
+ /* eslint-disable @typescript-eslint/naming-convention */
742
+ variables: JSON.stringify({
743
+ userId: id,
744
+ count: count,
745
+ cursor: cursor,
746
+ includePromotedContent: false,
747
+ withClientEventToken: false,
748
+ withBirdwatchNotes: false,
749
+ withVoice: false,
750
+ withV2Timeline: false,
751
+ }),
752
+ features: JSON.stringify({
753
+ rweb_video_screen_enabled: false,
754
+ profile_label_improvements_pcf_label_in_post_enabled: true,
755
+ responsive_web_profile_redirect_enabled: false,
756
+ rweb_tipjar_consumption_enabled: true,
757
+ verified_phone_label_enabled: true,
758
+ creator_subscriptions_tweet_preview_api_enabled: true,
759
+ responsive_web_graphql_timeline_navigation_enabled: true,
760
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
761
+ premium_content_api_read_enabled: false,
762
+ communities_web_enable_tweet_community_results_fetch: true,
763
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
764
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
765
+ responsive_web_grok_analyze_post_followups_enabled: true,
766
+ responsive_web_jetfuel_frame: true,
767
+ responsive_web_grok_share_attachment_enabled: true,
768
+ articles_preview_enabled: true,
769
+ responsive_web_edit_tweet_api_enabled: true,
770
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
771
+ view_counts_everywhere_api_enabled: true,
772
+ longform_notetweets_consumption_enabled: true,
773
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
774
+ tweet_awards_web_tipping_enabled: false,
775
+ responsive_web_grok_show_grok_translated_post: false,
776
+ responsive_web_grok_analysis_button_from_backend: true,
777
+ creator_subscriptions_quote_tweet_preview_enabled: false,
778
+ freedom_of_speech_not_reach_fetch_enabled: true,
779
+ standardized_nudges_misinfo: true,
780
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
781
+ longform_notetweets_rich_text_read_enabled: true,
782
+ longform_notetweets_inline_media_enabled: true,
783
+ responsive_web_grok_image_annotation_enabled: true,
784
+ responsive_web_grok_imagine_annotation_enabled: true,
785
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
786
+ responsive_web_enhance_cards_enabled: false,
787
+ }),
788
+ fieldToggles: { withArticlePlainText: false },
789
+ /* eslint-enable @typescript-eslint/naming-convention */
790
+ },
791
+ };
792
+ }
793
+
794
+ /**
795
+ * @param count - The number of notifications to fetch.
796
+ * @param cursor - The cursor to the batch of notifications to fetch.
797
+ */
798
+ public static notifications(count?: number, cursor?: string): FetchConfig {
799
+ return {
800
+ method: 'get',
801
+ url: 'https://x.com/i/api/graphql/Ev6UMJRROInk_RMH2oVbBg/NotificationsTimeline',
802
+ params: {
803
+ /* eslint-disable @typescript-eslint/naming-convention */
804
+ variables: JSON.stringify({
805
+ timeline_type: 'All',
806
+ count: count,
807
+ cursor: cursor,
808
+ }),
809
+ features: JSON.stringify({
810
+ rweb_video_screen_enabled: false,
811
+ profile_label_improvements_pcf_label_in_post_enabled: true,
812
+ responsive_web_profile_redirect_enabled: false,
813
+ rweb_tipjar_consumption_enabled: true,
814
+ verified_phone_label_enabled: true,
815
+ creator_subscriptions_tweet_preview_api_enabled: true,
816
+ responsive_web_graphql_timeline_navigation_enabled: true,
817
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
818
+ premium_content_api_read_enabled: false,
819
+ communities_web_enable_tweet_community_results_fetch: true,
820
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
821
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
822
+ responsive_web_grok_analyze_post_followups_enabled: true,
823
+ responsive_web_jetfuel_frame: true,
824
+ responsive_web_grok_share_attachment_enabled: true,
825
+ articles_preview_enabled: true,
826
+ responsive_web_edit_tweet_api_enabled: true,
827
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
828
+ view_counts_everywhere_api_enabled: true,
829
+ longform_notetweets_consumption_enabled: true,
830
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
831
+ tweet_awards_web_tipping_enabled: false,
832
+ responsive_web_grok_show_grok_translated_post: false,
833
+ responsive_web_grok_analysis_button_from_backend: true,
834
+ creator_subscriptions_quote_tweet_preview_enabled: false,
835
+ freedom_of_speech_not_reach_fetch_enabled: true,
836
+ standardized_nudges_misinfo: true,
837
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
838
+ longform_notetweets_rich_text_read_enabled: true,
839
+ longform_notetweets_inline_media_enabled: true,
840
+ responsive_web_grok_image_annotation_enabled: true,
841
+ responsive_web_grok_imagine_annotation_enabled: true,
842
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
843
+ responsive_web_enhance_cards_enabled: false,
844
+ }),
845
+ /* eslint-enable @typescript-eslint/naming-convention */
846
+ },
847
+ };
848
+ }
849
+
850
+ /**
851
+ * @param count - The number of timeline items to fetch. Only works as a lower limit when used with a cursor.
852
+ * @param cursor - The cursor to the batch of recommended timeline items to fetch.
853
+ */
854
+ public static recommended(count?: number, cursor?: string): FetchConfig {
855
+ return {
856
+ method: 'get',
857
+ url: 'https://x.com/i/api/graphql/V7xdnRnvW6a8vIsMr9xK7A/HomeTimeline',
858
+ params: {
859
+ /* eslint-disable @typescript-eslint/naming-convention */
860
+ variables: JSON.stringify({
861
+ count: count,
862
+ cursor: cursor,
863
+ includePromotedContent: false,
864
+ latestControlAvailable: true,
865
+ withCommunity: false,
866
+ seenTweetIds: [],
867
+ }),
868
+ features: JSON.stringify({
869
+ rweb_video_screen_enabled: false,
870
+ profile_label_improvements_pcf_label_in_post_enabled: true,
871
+ responsive_web_profile_redirect_enabled: false,
872
+ rweb_tipjar_consumption_enabled: true,
873
+ verified_phone_label_enabled: true,
874
+ creator_subscriptions_tweet_preview_api_enabled: true,
875
+ responsive_web_graphql_timeline_navigation_enabled: true,
876
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
877
+ premium_content_api_read_enabled: false,
878
+ communities_web_enable_tweet_community_results_fetch: true,
879
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
880
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
881
+ responsive_web_grok_analyze_post_followups_enabled: true,
882
+ responsive_web_jetfuel_frame: true,
883
+ responsive_web_grok_share_attachment_enabled: true,
884
+ articles_preview_enabled: true,
885
+ responsive_web_edit_tweet_api_enabled: true,
886
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
887
+ view_counts_everywhere_api_enabled: true,
888
+ longform_notetweets_consumption_enabled: true,
889
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
890
+ tweet_awards_web_tipping_enabled: false,
891
+ responsive_web_grok_show_grok_translated_post: false,
892
+ responsive_web_grok_analysis_button_from_backend: true,
893
+ creator_subscriptions_quote_tweet_preview_enabled: false,
894
+ freedom_of_speech_not_reach_fetch_enabled: true,
895
+ standardized_nudges_misinfo: true,
896
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
897
+ longform_notetweets_rich_text_read_enabled: true,
898
+ longform_notetweets_inline_media_enabled: true,
899
+ responsive_web_grok_image_annotation_enabled: true,
900
+ responsive_web_grok_imagine_annotation_enabled: true,
901
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
902
+ responsive_web_enhance_cards_enabled: false,
903
+ }),
904
+ /* eslint-enable @typescript-eslint/naming-convention */
905
+ },
906
+ };
907
+ }
908
+
909
+ public static scheduled(): FetchConfig {
910
+ return {
911
+ method: 'get',
912
+ url: 'https://x.com/i/api/graphql/ITtjAzvlZni2wWXwf295Qg/FetchScheduledTweets?variables=%7B%22ascending%22%3Atrue%7D',
913
+ params: {
914
+ variables: JSON.stringify({ ascending: true }),
915
+ },
916
+ };
917
+ }
918
+
919
+ /**
920
+ * @param userName - The username to search for.
921
+ * @param count - The number of user matches to fetch. Only works as a lower limit when used with a cursor.
922
+ * @param cursor - The cursor to the batch of results to fetch.
923
+ */
924
+ public static search(userName: string, count?: number, cursor?: string): FetchConfig {
925
+ return {
926
+ method: 'get',
927
+ url: 'https://x.com/i/api/graphql/M1jEez78PEfVfbQLvlWMvQ/SearchTimeline',
928
+ params: {
929
+ /* eslint-disable @typescript-eslint/naming-convention */
930
+ variables: JSON.stringify({
931
+ rawQuery: userName,
932
+ count: count,
933
+ cursor: cursor,
934
+ querySource: 'typed_query',
935
+ product: 'People',
936
+ withGrokTranslatedBio: false,
937
+ }),
938
+ features: JSON.stringify({
939
+ rweb_video_screen_enabled: false,
940
+ profile_label_improvements_pcf_label_in_post_enabled: true,
941
+ responsive_web_profile_redirect_enabled: false,
942
+ rweb_tipjar_consumption_enabled: true,
943
+ verified_phone_label_enabled: true,
944
+ creator_subscriptions_tweet_preview_api_enabled: true,
945
+ responsive_web_graphql_timeline_navigation_enabled: true,
946
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
947
+ premium_content_api_read_enabled: false,
948
+ communities_web_enable_tweet_community_results_fetch: true,
949
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
950
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
951
+ responsive_web_grok_analyze_post_followups_enabled: true,
952
+ responsive_web_jetfuel_frame: true,
953
+ responsive_web_grok_share_attachment_enabled: true,
954
+ articles_preview_enabled: true,
955
+ responsive_web_edit_tweet_api_enabled: true,
956
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
957
+ view_counts_everywhere_api_enabled: true,
958
+ longform_notetweets_consumption_enabled: true,
959
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
960
+ tweet_awards_web_tipping_enabled: false,
961
+ responsive_web_grok_show_grok_translated_post: false,
962
+ responsive_web_grok_analysis_button_from_backend: true,
963
+ creator_subscriptions_quote_tweet_preview_enabled: false,
964
+ freedom_of_speech_not_reach_fetch_enabled: true,
965
+ standardized_nudges_misinfo: true,
966
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
967
+ longform_notetweets_rich_text_read_enabled: true,
968
+ longform_notetweets_inline_media_enabled: true,
969
+ responsive_web_grok_image_annotation_enabled: true,
970
+ responsive_web_grok_imagine_annotation_enabled: true,
971
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
972
+ responsive_web_enhance_cards_enabled: false,
973
+ }),
974
+ /* eslint-enable @typescript-eslint/naming-convention */
975
+ },
976
+ };
977
+ }
978
+
979
+ /**
980
+ * @param id - The id of the user whose subscriptions are to be fetched.
981
+ * @param count - The number of subscriptions to fetch. Only works as a lower limit when used with a cursor.
982
+ * @param cursor - The cursor to the batch of subscriptions to fetch.
983
+ */
984
+ public static subscriptions(id: string, count?: number, cursor?: string): FetchConfig {
985
+ return {
986
+ method: 'get',
987
+ url: 'https://x.com/i/api/graphql/fl06vhYypYRcRxgLKO011Q/UserCreatorSubscriptions',
988
+ params: {
989
+ /* eslint-disable @typescript-eslint/naming-convention */
990
+ variables: JSON.stringify({
991
+ userId: id,
992
+ count: count,
993
+ cursor: cursor,
994
+ includePromotedContent: false,
995
+ }),
996
+ features: JSON.stringify({
997
+ rweb_video_screen_enabled: false,
998
+ profile_label_improvements_pcf_label_in_post_enabled: true,
999
+ responsive_web_profile_redirect_enabled: false,
1000
+ rweb_tipjar_consumption_enabled: true,
1001
+ verified_phone_label_enabled: true,
1002
+ creator_subscriptions_tweet_preview_api_enabled: true,
1003
+ responsive_web_graphql_timeline_navigation_enabled: true,
1004
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
1005
+ premium_content_api_read_enabled: false,
1006
+ communities_web_enable_tweet_community_results_fetch: true,
1007
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
1008
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
1009
+ responsive_web_grok_analyze_post_followups_enabled: true,
1010
+ responsive_web_jetfuel_frame: true,
1011
+ responsive_web_grok_share_attachment_enabled: true,
1012
+ articles_preview_enabled: true,
1013
+ responsive_web_edit_tweet_api_enabled: true,
1014
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
1015
+ view_counts_everywhere_api_enabled: true,
1016
+ longform_notetweets_consumption_enabled: true,
1017
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
1018
+ tweet_awards_web_tipping_enabled: false,
1019
+ responsive_web_grok_show_grok_translated_post: false,
1020
+ responsive_web_grok_analysis_button_from_backend: true,
1021
+ creator_subscriptions_quote_tweet_preview_enabled: false,
1022
+ freedom_of_speech_not_reach_fetch_enabled: true,
1023
+ standardized_nudges_misinfo: true,
1024
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
1025
+ longform_notetweets_rich_text_read_enabled: true,
1026
+ longform_notetweets_inline_media_enabled: true,
1027
+ responsive_web_grok_image_annotation_enabled: true,
1028
+ responsive_web_grok_imagine_annotation_enabled: true,
1029
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
1030
+ responsive_web_enhance_cards_enabled: false,
1031
+ }),
1032
+ /* eslint-enable @typescript-eslint/naming-convention */
1033
+ },
1034
+ };
1035
+ }
1036
+
1037
+ /**
1038
+ * @param id - The id of the user whose timeline tweets are to be fetched.
1039
+ * @param count - The number of timeline tweets to fetch. Only works as a lower limit when used with a cursor.
1040
+ * @param cursor - The cursor to the batch of timeline tweets to fetch.
1041
+ */
1042
+ public static tweets(id: string, count?: number, cursor?: string): FetchConfig {
1043
+ return {
1044
+ method: 'get',
1045
+ url: 'https://x.com/i/api/graphql/-V26I6Pb5xDZ3C7BWwCQ_Q/UserTweets',
1046
+ params: {
1047
+ /* eslint-disable @typescript-eslint/naming-convention */
1048
+ variables: JSON.stringify({
1049
+ userId: id,
1050
+ count: count,
1051
+ cursor: cursor,
1052
+ includePromotedContent: false,
1053
+ withQuickPromoteEligibilityTweetFields: false,
1054
+ withVoice: false,
1055
+ withV2Timeline: false,
1056
+ }),
1057
+ features: JSON.stringify({
1058
+ rweb_video_screen_enabled: false,
1059
+ profile_label_improvements_pcf_label_in_post_enabled: true,
1060
+ responsive_web_profile_redirect_enabled: false,
1061
+ rweb_tipjar_consumption_enabled: true,
1062
+ verified_phone_label_enabled: true,
1063
+ creator_subscriptions_tweet_preview_api_enabled: true,
1064
+ responsive_web_graphql_timeline_navigation_enabled: true,
1065
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
1066
+ premium_content_api_read_enabled: false,
1067
+ communities_web_enable_tweet_community_results_fetch: true,
1068
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
1069
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
1070
+ responsive_web_grok_analyze_post_followups_enabled: true,
1071
+ responsive_web_jetfuel_frame: true,
1072
+ responsive_web_grok_share_attachment_enabled: true,
1073
+ articles_preview_enabled: true,
1074
+ responsive_web_edit_tweet_api_enabled: true,
1075
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
1076
+ view_counts_everywhere_api_enabled: true,
1077
+ longform_notetweets_consumption_enabled: true,
1078
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
1079
+ tweet_awards_web_tipping_enabled: false,
1080
+ responsive_web_grok_show_grok_translated_post: false,
1081
+ responsive_web_grok_analysis_button_from_backend: true,
1082
+ creator_subscriptions_quote_tweet_preview_enabled: false,
1083
+ freedom_of_speech_not_reach_fetch_enabled: true,
1084
+ standardized_nudges_misinfo: true,
1085
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
1086
+ longform_notetweets_rich_text_read_enabled: true,
1087
+ longform_notetweets_inline_media_enabled: true,
1088
+ responsive_web_grok_image_annotation_enabled: true,
1089
+ responsive_web_grok_imagine_annotation_enabled: true,
1090
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
1091
+ responsive_web_enhance_cards_enabled: false,
1092
+ }),
1093
+ fieldToggles: { withArticlePlainText: false },
1094
+ /* eslint-enable @typescript-eslint/naming-convention */
1095
+ },
1096
+ };
1097
+ }
1098
+
1099
+ /**
1100
+ * @param id - The id of the user whose timeline tweets and replies are to be fetched.
1101
+ * @param count - The number of timeline tweets and replies to fetch. Only works as a lower limit when used with a cursor.
1102
+ * @param cursor - The cursor to the batch of timeline tweets and replies to fetch.
1103
+ */
1104
+ public static tweetsAndReplies(id: string, count?: number, cursor?: string): FetchConfig {
1105
+ return {
1106
+ method: 'get',
1107
+ url: 'https://x.com/i/api/graphql/61HQnvcGP870hiE-hCbG4A/UserTweetsAndReplies',
1108
+ params: {
1109
+ /* eslint-disable @typescript-eslint/naming-convention */
1110
+ variables: JSON.stringify({
1111
+ userId: id,
1112
+ count: count,
1113
+ cursor: cursor,
1114
+ includePromotedContent: false,
1115
+ withCommunity: false,
1116
+ withVoice: false,
1117
+ withV2Timeline: false,
1118
+ }),
1119
+ features: JSON.stringify({
1120
+ rweb_video_screen_enabled: false,
1121
+ profile_label_improvements_pcf_label_in_post_enabled: true,
1122
+ responsive_web_profile_redirect_enabled: false,
1123
+ rweb_tipjar_consumption_enabled: true,
1124
+ verified_phone_label_enabled: true,
1125
+ creator_subscriptions_tweet_preview_api_enabled: true,
1126
+ responsive_web_graphql_timeline_navigation_enabled: true,
1127
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
1128
+ premium_content_api_read_enabled: false,
1129
+ communities_web_enable_tweet_community_results_fetch: true,
1130
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
1131
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
1132
+ responsive_web_grok_analyze_post_followups_enabled: true,
1133
+ responsive_web_jetfuel_frame: true,
1134
+ responsive_web_grok_share_attachment_enabled: true,
1135
+ articles_preview_enabled: true,
1136
+ responsive_web_edit_tweet_api_enabled: true,
1137
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
1138
+ view_counts_everywhere_api_enabled: true,
1139
+ longform_notetweets_consumption_enabled: true,
1140
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
1141
+ tweet_awards_web_tipping_enabled: false,
1142
+ responsive_web_grok_show_grok_translated_post: false,
1143
+ responsive_web_grok_analysis_button_from_backend: true,
1144
+ creator_subscriptions_quote_tweet_preview_enabled: false,
1145
+ freedom_of_speech_not_reach_fetch_enabled: true,
1146
+ standardized_nudges_misinfo: true,
1147
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
1148
+ longform_notetweets_rich_text_read_enabled: true,
1149
+ longform_notetweets_inline_media_enabled: true,
1150
+ responsive_web_grok_image_annotation_enabled: true,
1151
+ responsive_web_grok_imagine_annotation_enabled: true,
1152
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
1153
+ responsive_web_enhance_cards_enabled: false,
1154
+ }),
1155
+ fieldToggles: { withArticlePlainText: false },
1156
+ /* eslint-enable @typescript-eslint/naming-convention */
1157
+ },
1158
+ };
1159
+ }
1160
+
1161
+ /**
1162
+ * @param id - The id of the user to be unfollowed.
1163
+ */
1164
+ public static unfollow(id: string): FetchConfig {
1165
+ return {
1166
+ method: 'post',
1167
+ url: 'https://x.com/i/api/1.1/friendships/destroy.json',
1168
+ body: qs.stringify({
1169
+ /* eslint-disable @typescript-eslint/naming-convention */
1170
+ user_id: id,
1171
+ /* eslint-enable @typescript-eslint/naming-convention */
1172
+ }),
1173
+ };
1174
+ }
1175
+
1176
+ /**
1177
+ * @param options - The profile update options.
1178
+ */
1179
+ public static updateProfile(options: IProfileUpdateOptions): FetchConfig {
1180
+ return {
1181
+ method: 'post',
1182
+ url: 'https://x.com/i/api/1.1/account/update_profile.json',
1183
+ body: qs.stringify({
1184
+ ...(options.name && { name: options.name }),
1185
+ ...(options.url && { url: options.url }),
1186
+ ...(options.location && { location: options.location }),
1187
+ ...(options.description && { description: options.description }),
1188
+ } as Record<string, string>),
1189
+ };
1190
+ }
1191
+ }