rettiwt-api 7.0.3 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +38 -10
  2. package/dist/collections/Extractors.d.ts +14 -0
  3. package/dist/collections/Extractors.js +7 -0
  4. package/dist/collections/Extractors.js.map +1 -1
  5. package/dist/collections/Groups.js +7 -0
  6. package/dist/collections/Groups.js.map +1 -1
  7. package/dist/collections/Requests.js +7 -0
  8. package/dist/collections/Requests.js.map +1 -1
  9. package/dist/commands/List.js +87 -0
  10. package/dist/commands/List.js.map +1 -1
  11. package/dist/commands/Tweet.js +14 -0
  12. package/dist/commands/Tweet.js.map +1 -1
  13. package/dist/commands/User.js +13 -0
  14. package/dist/commands/User.js.map +1 -1
  15. package/dist/enums/Resource.d.ts +7 -0
  16. package/dist/enums/Resource.js +7 -0
  17. package/dist/enums/Resource.js.map +1 -1
  18. package/dist/index.d.ts +7 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/models/args/PostArgs.d.ts +31 -1
  21. package/dist/models/args/PostArgs.js +43 -1
  22. package/dist/models/args/PostArgs.js.map +1 -1
  23. package/dist/requests/List.d.ts +22 -0
  24. package/dist/requests/List.js +106 -0
  25. package/dist/requests/List.js.map +1 -1
  26. package/dist/requests/Tweet.d.ts +4 -0
  27. package/dist/requests/Tweet.js +59 -0
  28. package/dist/requests/Tweet.js.map +1 -1
  29. package/dist/requests/User.d.ts +4 -0
  30. package/dist/requests/User.js +15 -0
  31. package/dist/requests/User.js.map +1 -1
  32. package/dist/services/public/ListService.d.ts +136 -0
  33. package/dist/services/public/ListService.js +175 -0
  34. package/dist/services/public/ListService.js.map +1 -1
  35. package/dist/services/public/TweetService.d.ts +26 -0
  36. package/dist/services/public/TweetService.js +33 -0
  37. package/dist/services/public/TweetService.js.map +1 -1
  38. package/dist/services/public/UserService.d.ts +28 -0
  39. package/dist/services/public/UserService.js +35 -0
  40. package/dist/services/public/UserService.js.map +1 -1
  41. package/dist/types/args/PostArgs.d.ts +50 -0
  42. package/dist/types/raw/list/Create.d.ts +14 -0
  43. package/dist/types/raw/list/Create.js +4 -0
  44. package/dist/types/raw/list/Create.js.map +1 -0
  45. package/dist/types/raw/list/Delete.d.ts +10 -0
  46. package/dist/types/raw/list/Delete.js +4 -0
  47. package/dist/types/raw/list/Delete.js.map +1 -0
  48. package/dist/types/raw/list/Mute.d.ts +10 -0
  49. package/dist/types/raw/list/Mute.js +3 -0
  50. package/dist/types/raw/list/Mute.js.map +1 -0
  51. package/dist/types/raw/list/Unmute.d.ts +10 -0
  52. package/dist/types/raw/list/Unmute.js +3 -0
  53. package/dist/types/raw/list/Unmute.js.map +1 -0
  54. package/dist/types/raw/list/Update.d.ts +11 -0
  55. package/dist/types/raw/list/Update.js +3 -0
  56. package/dist/types/raw/list/Update.js.map +1 -0
  57. package/dist/types/raw/tweet/History.d.ts +48 -0
  58. package/dist/types/raw/tweet/History.js +4 -0
  59. package/dist/types/raw/tweet/History.js.map +1 -0
  60. package/dist/types/raw/user/RemoveFollower.d.ts +13 -0
  61. package/dist/types/raw/user/RemoveFollower.js +4 -0
  62. package/dist/types/raw/user/RemoveFollower.js.map +1 -0
  63. package/package.json +1 -1
  64. package/src/collections/Extractors.ts +16 -0
  65. package/src/collections/Groups.ts +7 -0
  66. package/src/collections/Requests.ts +7 -0
  67. package/src/commands/List.ts +100 -0
  68. package/src/commands/Tweet.ts +14 -0
  69. package/src/commands/User.ts +13 -0
  70. package/src/enums/Resource.ts +7 -0
  71. package/src/index.ts +7 -1
  72. package/src/models/args/PostArgs.ts +53 -1
  73. package/src/requests/List.ts +117 -0
  74. package/src/requests/Tweet.ts +60 -0
  75. package/src/requests/User.ts +16 -0
  76. package/src/services/public/ListService.ts +201 -0
  77. package/src/services/public/TweetService.ts +38 -0
  78. package/src/services/public/UserService.ts +40 -0
  79. package/src/types/args/PostArgs.ts +58 -0
  80. package/src/types/raw/list/Create.ts +16 -0
  81. package/src/types/raw/list/Delete.ts +12 -0
  82. package/src/types/raw/list/Mute.ts +10 -0
  83. package/src/types/raw/list/Unmute.ts +10 -0
  84. package/src/types/raw/list/Update.ts +12 -0
  85. package/src/types/raw/tweet/History.ts +57 -0
  86. package/src/types/raw/user/RemoveFollower.ts +15 -0
@@ -2,6 +2,20 @@ import { Command, createCommand } from 'commander';
2
2
 
3
3
  import { output } from '../helper/CliUtils';
4
4
  import { Rettiwt } from '../Rettiwt';
5
+ import { IListUpdates } from '../types/args/PostArgs';
6
+
7
+ type ListCreateOptions = {
8
+ description?: boolean | string;
9
+ private?: boolean;
10
+ };
11
+
12
+ type ListUpdateOptions = ListCreateOptions & {
13
+ public?: boolean;
14
+ };
15
+
16
+ function getDescription(description?: boolean | string): string | undefined {
17
+ return typeof description === 'string' ? description : undefined;
18
+ }
5
19
 
6
20
  /**
7
21
  * Creates a new 'list' command which uses the given Rettiwt instance.
@@ -13,6 +27,92 @@ function createListCommand(rettiwt: Rettiwt): Command {
13
27
  // Creating the 'list' command
14
28
  const list = createCommand('list').description('Access resources related to lists');
15
29
 
30
+ // Create
31
+ list.command('create')
32
+ .description('Create a new list')
33
+ .argument('<name>', 'The name of the tweet list')
34
+ .option('-d, --description [string]', 'The description of the tweet list')
35
+ .option('--private', 'Create a private list')
36
+ .action(async (name: string, options?: ListCreateOptions) => {
37
+ try {
38
+ const id = await rettiwt.list.create({
39
+ name: name,
40
+ description: getDescription(options?.description),
41
+ isPrivate: options?.private,
42
+ });
43
+ output(id);
44
+ } catch (error) {
45
+ output(error);
46
+ }
47
+ });
48
+
49
+ // Update
50
+ list.command('update')
51
+ .description('Update a list')
52
+ .argument('<id>', 'The ID of the tweet list')
53
+ .argument('[name]', 'The updated name of the tweet list')
54
+ .option('-d, --description [string]', 'The updated description of the tweet list')
55
+ .option('--private', 'Update to a private list')
56
+ .option('--public', 'Update to a public list')
57
+ .action(async (id: string, name?: string, options?: ListUpdateOptions) => {
58
+ try {
59
+ if (options?.private && options?.public) {
60
+ throw new Error('List cannot be both private and public');
61
+ }
62
+
63
+ const updates: IListUpdates = {
64
+ ...(name !== undefined ? { name: name } : {}),
65
+ ...(typeof options?.description === 'string' ? { description: options.description } : {}),
66
+ ...(options?.private ? { isPrivate: true } : {}),
67
+ ...(options?.public ? { isPrivate: false } : {}),
68
+ };
69
+
70
+ const details = await rettiwt.list.update(id, updates);
71
+ output(details);
72
+ } catch (error) {
73
+ output(error);
74
+ }
75
+ });
76
+
77
+ // Delete
78
+ list.command('delete')
79
+ .description('Delete a list')
80
+ .argument('<id>', 'The ID of the tweet list')
81
+ .action(async (id: string) => {
82
+ try {
83
+ const deleted = await rettiwt.list.delete(id);
84
+ output(deleted);
85
+ } catch (error) {
86
+ output(error);
87
+ }
88
+ });
89
+
90
+ // Mute
91
+ list.command('mute')
92
+ .description('Mute a list')
93
+ .argument('<id>', 'The ID of the tweet list')
94
+ .action(async (id: string) => {
95
+ try {
96
+ const muted = await rettiwt.list.mute(id);
97
+ output(muted);
98
+ } catch (error) {
99
+ output(error);
100
+ }
101
+ });
102
+
103
+ // Unmute
104
+ list.command('unmute')
105
+ .description('Unmute a list')
106
+ .argument('<id>', 'The ID of the tweet list')
107
+ .action(async (id: string) => {
108
+ try {
109
+ const unmuted = await rettiwt.list.unmute(id);
110
+ output(unmuted);
111
+ } catch (error) {
112
+ output(error);
113
+ }
114
+ });
115
+
16
116
  // Add member
17
117
  list.command('add-member')
18
118
  .description('Add a new member to a list')
@@ -55,6 +55,20 @@ function createTweetCommand(rettiwt: Rettiwt): Command {
55
55
  }
56
56
  });
57
57
 
58
+ // History
59
+ tweet
60
+ .command('history')
61
+ .description('Fetch the edit history of a tweet')
62
+ .argument('<id>', 'The id of the tweet')
63
+ .action(async (id: string) => {
64
+ try {
65
+ const tweets = await rettiwt.tweet.history(id);
66
+ output(tweets);
67
+ } catch (error) {
68
+ output(error);
69
+ }
70
+ });
71
+
58
72
  // Like
59
73
  tweet
60
74
  .command('like')
@@ -278,6 +278,19 @@ function createUserCommand(rettiwt: Rettiwt): Command {
278
278
  }
279
279
  });
280
280
 
281
+ // Remove Follower
282
+ user.command('remove-follower')
283
+ .description("Remove a user from the authenticated user's followers")
284
+ .argument('<id>', 'The user to remove as a follower')
285
+ .action(async (id: string) => {
286
+ try {
287
+ const result = await rettiwt.user.removeFollower(id);
288
+ output(result);
289
+ } catch (error) {
290
+ output(error);
291
+ }
292
+ });
293
+
281
294
  // Replies
282
295
  user.command('replies')
283
296
  .description('Fetch the replies timeline the given user')
@@ -5,11 +5,16 @@
5
5
  */
6
6
  export enum ResourceType {
7
7
  // LIST
8
+ LIST_CREATE = 'LIST_CREATE',
9
+ LIST_DELETE = 'LIST_DELETE',
8
10
  LIST_DETAILS = 'LIST_DETAILS',
9
11
  LIST_MEMBER_ADD = 'LIST_MEMBER_ADD',
10
12
  LIST_MEMBER_REMOVE = 'LIST_MEMBER_REMOVE',
11
13
  LIST_MEMBERS = 'LIST_MEMBERS',
14
+ LIST_MUTE = 'LIST_MUTE',
12
15
  LIST_TWEETS = 'LIST_TWEETS',
16
+ LIST_UNMUTE = 'LIST_UNMUTE',
17
+ LIST_UPDATE = 'LIST_UPDATE',
13
18
 
14
19
  // MEDIA
15
20
  MEDIA_UPLOAD_APPEND = 'MEDIA_UPLOAD_APPEND',
@@ -30,6 +35,7 @@ export enum ResourceType {
30
35
  TWEET_DETAILS = 'TWEET_DETAILS',
31
36
  TWEET_DETAILS_ALT = 'TWEET_DETAILS_ALT',
32
37
  TWEET_DETAILS_BULK = 'TWEET_DETAILS_BULK',
38
+ TWEET_HISTORY = 'TWEET_HISTORY',
33
39
  TWEET_LIKE = 'TWEET_LIKE',
34
40
  TWEET_LIKERS = 'TWEET_LIKERS',
35
41
  TWEET_POST = 'TWEET_POST',
@@ -65,6 +71,7 @@ export enum ResourceType {
65
71
  USER_LISTS = 'USER_LISTS',
66
72
  USER_MEDIA = 'USER_MEDIA',
67
73
  USER_NOTIFICATIONS = 'USER_NOTIFICATIONS',
74
+ USER_REMOVE_FOLLOWER = 'USER_REMOVE_FOLLOWER',
68
75
  USER_SEARCH = 'USER_SEARCH',
69
76
  USER_SUBSCRIPTIONS = 'USER_SUBSCRIPTIONS',
70
77
  USER_TIMELINE = 'USER_TIMELINE',
package/src/index.ts CHANGED
@@ -82,16 +82,22 @@ export { ITimelineTweet as IRawTimelineTweet } from './types/raw/composite/Timel
82
82
  export { ITimelineUser as IRawTimelineUser } from './types/raw/composite/TimelineUser';
83
83
  export { IResponse as IRawResponse } from './types/raw/generic/Response';
84
84
  export { IListMemberAddResponse as IRawListMemberAddResponse } from './types/raw/list/AddMember';
85
- export { IListMemberRemoveResponse as IRawListMemberRemoveResponse } from './types/raw/list/RemoveMember';
85
+ export { IListCreateResponse as IRawListCreateResponse } from './types/raw/list/Create';
86
+ export { IListDeleteResponse as IRawListDeleteResponse } from './types/raw/list/Delete';
86
87
  export { IListDetailsResponse as IRawListDetailsResponse } from './types/raw/list/Details';
87
88
  export { IListMembersResponse as IRawListMembersResponse } from './types/raw/list/Members';
89
+ export { IListMuteResponse as IRawListMuteResponse } from './types/raw/list/Mute';
90
+ export { IListMemberRemoveResponse as IRawListMemberRemoveResponse } from './types/raw/list/RemoveMember';
88
91
  export { IListTweetsResponse as IRawListTweetsResponse } from './types/raw/list/Tweets';
92
+ export { IListUnmuteResponse as IRawListUnmuteResponse } from './types/raw/list/Unmute';
93
+ export { IListUpdateResponse as IRawListUpdateResponse } from './types/raw/list/Update';
89
94
  export { IMediaFinalizeUploadResponse as IRawMediaFinalizeUploadResponse } from './types/raw/media/FinalizeUpload';
90
95
  export { IMediaInitializeUploadResponse as IRawMediaInitializeUploadResponse } from './types/raw/media/InitalizeUpload';
91
96
  export { IMediaLiveVideoStreamResponse as IRawMediaLiveVideoStreamResponse } from './types/raw/media/LiveVideoStream';
92
97
  export { IAudioSpaceByIdResponse as IRawSpaceDetailsResponse } from './types/raw/space/AudioSpaceById';
93
98
  export { ITweetDetailsResponse as IRawTweetDetailsResponse } from './types/raw/tweet/Details';
94
99
  export { ITweetDetailsBulkResponse as IRawTweetDetailsBulkResponse } from './types/raw/tweet/DetailsBulk';
100
+ export { ITweetHistoryResponse as IRawTweetHistoryResponse } from './types/raw/tweet/History';
95
101
  export { ITweetLikeResponse as IRawTweetLikeResponse } from './types/raw/tweet/Like';
96
102
  export { ITweetLikersResponse as IRawTweetLikersResponse } from './types/raw/tweet/Likers';
97
103
  export { ITweetPostResponse as IRawTweetPostResponse } from './types/raw/tweet/Post';
@@ -1,4 +1,12 @@
1
- import { IChangePasswordArgs, INewTweet, INewTweetMedia, IPostArgs, IUploadArgs } from '../../types/args/PostArgs';
1
+ import {
2
+ IChangePasswordArgs,
3
+ IListUpdates,
4
+ INewList,
5
+ INewTweet,
6
+ INewTweetMedia,
7
+ IPostArgs,
8
+ IUploadArgs,
9
+ } from '../../types/args/PostArgs';
2
10
 
3
11
  import { ProfileUpdateOptions } from './ProfileArgs';
4
12
 
@@ -11,6 +19,8 @@ export class PostArgs implements IPostArgs {
11
19
  public changePassword?: ChangePasswordArgs;
12
20
  public conversationId?: string;
13
21
  public id?: string;
22
+ public list?: NewList;
23
+ public listUpdates?: ListUpdates;
14
24
  public profileBanner?: string;
15
25
  public profileImage?: string;
16
26
  public profileOptions?: ProfileUpdateOptions;
@@ -25,6 +35,7 @@ export class PostArgs implements IPostArgs {
25
35
  */
26
36
  public constructor(args: IPostArgs) {
27
37
  this.id = args.id;
38
+ this.list = args.list ? new NewList(args.list) : undefined;
28
39
  this.tweet = args.tweet ? new NewTweet(args.tweet) : undefined;
29
40
  this.upload = args.upload ? new UploadArgs(args.upload) : undefined;
30
41
  this.userId = args.userId;
@@ -34,6 +45,7 @@ export class PostArgs implements IPostArgs {
34
45
  this.profileImage = PostArgs._validateNonEmptyString(args.profileImage, 'Profile image');
35
46
  this.profileBanner = PostArgs._validateNonEmptyString(args.profileBanner, 'Profile banner');
36
47
  this.changePassword = args.changePassword ? new ChangePasswordArgs(args.changePassword) : undefined;
48
+ this.listUpdates = args.listUpdates ? new ListUpdates(args.listUpdates) : undefined;
37
49
  }
38
50
 
39
51
  /**
@@ -61,6 +73,46 @@ export class PostArgs implements IPostArgs {
61
73
  }
62
74
  }
63
75
 
76
+ /**
77
+ * Configuration for the list to be created.
78
+ *
79
+ * @public
80
+ */
81
+ export class NewList implements INewList {
82
+ public description?: string;
83
+ public isPrivate: boolean;
84
+ public name: string;
85
+
86
+ /**
87
+ * @param newList - The args specifying the list to be created.
88
+ */
89
+ public constructor(newList: INewList) {
90
+ this.name = newList.name;
91
+ this.description = newList.description;
92
+ this.isPrivate = newList.isPrivate ?? false;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Configuration for the updates to apply to an existing list.
98
+ *
99
+ * @public
100
+ */
101
+ export class ListUpdates implements IListUpdates {
102
+ public description?: string;
103
+ public isPrivate?: boolean;
104
+ public name?: string;
105
+
106
+ /**
107
+ * @param updates - The updates to apply to the target list.
108
+ */
109
+ public constructor(updates: IListUpdates) {
110
+ this.name = updates.name;
111
+ this.description = updates.description;
112
+ this.isPrivate = updates.isPrivate;
113
+ }
114
+ }
115
+
64
116
  /**
65
117
  * Configuration for the new tweet to be posted.
66
118
  *
@@ -1,5 +1,7 @@
1
1
  import { AxiosRequestConfig } from 'axios';
2
2
 
3
+ import { IListUpdates, INewList } from '../types/args/PostArgs';
4
+
3
5
  /**
4
6
  * Collection of requests related to lists.
5
7
  *
@@ -35,6 +37,54 @@ export class ListRequests {
35
37
  };
36
38
  }
37
39
 
40
+ /**
41
+ * @param list - The details of the list to create.
42
+ */
43
+ public static create(list: INewList): AxiosRequestConfig {
44
+ return {
45
+ method: 'post',
46
+ headers: { referer: 'https://x.com/i/lists/create' },
47
+ url: 'https://x.com/i/api/graphql/4lSOF4GqldI-NbiFET4ofQ/CreateList',
48
+ data: {
49
+ /* eslint-disable @typescript-eslint/naming-convention */
50
+
51
+ variables: {
52
+ isPrivate: list.isPrivate ?? false,
53
+ name: list.name,
54
+ ...(list.description !== undefined ? { description: list.description } : {}),
55
+ },
56
+ features: {
57
+ profile_label_improvements_pcf_label_in_post_enabled: true,
58
+ responsive_web_profile_redirect_enabled: false,
59
+ rweb_tipjar_consumption_enabled: false,
60
+ verified_phone_label_enabled: false,
61
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
62
+ responsive_web_graphql_timeline_navigation_enabled: true,
63
+ },
64
+ queryId: '4lSOF4GqldI-NbiFET4ofQ',
65
+
66
+ /* eslint-enable @typescript-eslint/naming-convention */
67
+ },
68
+ };
69
+ }
70
+
71
+ /**
72
+ * @param id - The ID of the list to delete.
73
+ */
74
+ public static delete(id: string): AxiosRequestConfig {
75
+ return {
76
+ method: 'post',
77
+ headers: { referer: `https://x.com/i/lists/${id}/info` },
78
+ url: 'https://x.com/i/api/graphql/UnN9Th1BDbeLjpgjGSpL3Q/DeleteList',
79
+ data: {
80
+ variables: {
81
+ listId: id,
82
+ },
83
+ queryId: 'UnN9Th1BDbeLjpgjGSpL3Q',
84
+ },
85
+ };
86
+ }
87
+
38
88
  /**
39
89
  * @param id - The id of the list whose details are to be fetched.
40
90
  */
@@ -116,6 +166,23 @@ export class ListRequests {
116
166
  };
117
167
  }
118
168
 
169
+ /**
170
+ * @param id - The ID of the list to mute.
171
+ */
172
+ public static mute(id: string): AxiosRequestConfig {
173
+ return {
174
+ method: 'post',
175
+ headers: { referer: `https://x.com/i/lists/${id}` },
176
+ url: 'https://x.com/i/api/graphql/ZYyanJsskNUcltu9bliMLA/MuteList',
177
+ data: {
178
+ variables: {
179
+ listId: id,
180
+ },
181
+ queryId: 'ZYyanJsskNUcltu9bliMLA',
182
+ },
183
+ };
184
+ }
185
+
119
186
  /**
120
187
  * @param listId - The ID of the target list.
121
188
  * @param userId - The ID of the user to remove as a member.
@@ -202,4 +269,54 @@ export class ListRequests {
202
269
  paramsSerializer: { encode: encodeURIComponent },
203
270
  };
204
271
  }
272
+
273
+ /**
274
+ * @param id - The ID of the list to unmute.
275
+ */
276
+ public static unmute(id: string): AxiosRequestConfig {
277
+ return {
278
+ method: 'post',
279
+ headers: { referer: `https://x.com/i/lists/${id}` },
280
+ url: 'https://x.com/i/api/graphql/pMZrHRNsmEkXgbn3tOyr7Q/UnmuteList',
281
+ data: {
282
+ variables: {
283
+ listId: id,
284
+ },
285
+ queryId: 'pMZrHRNsmEkXgbn3tOyr7Q',
286
+ },
287
+ };
288
+ }
289
+
290
+ /**
291
+ * @param id - The ID of the list to update.
292
+ * @param updates - The updates to apply.
293
+ */
294
+ public static update(id: string, updates: IListUpdates): AxiosRequestConfig {
295
+ return {
296
+ method: 'post',
297
+ headers: { referer: `https://x.com/i/lists/${id}/info` },
298
+ url: 'https://x.com/i/api/graphql/UzVGAR_brbQw1n3mH_PqRA/UpdateList',
299
+ data: {
300
+ /* eslint-disable @typescript-eslint/naming-convention */
301
+
302
+ variables: {
303
+ listId: id,
304
+ ...(updates.isPrivate !== undefined ? { isPrivate: updates.isPrivate } : {}),
305
+ ...(updates.description !== undefined ? { description: updates.description } : {}),
306
+ ...(updates.name !== undefined ? { name: updates.name } : {}),
307
+ },
308
+ features: {
309
+ profile_label_improvements_pcf_label_in_post_enabled: true,
310
+ responsive_web_profile_redirect_enabled: false,
311
+ rweb_tipjar_consumption_enabled: false,
312
+ verified_phone_label_enabled: false,
313
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
314
+ responsive_web_graphql_timeline_navigation_enabled: true,
315
+ },
316
+ queryId: 'UzVGAR_brbQw1n3mH_PqRA',
317
+
318
+ /* eslint-enable @typescript-eslint/naming-convention */
319
+ },
320
+ };
321
+ }
205
322
  }
@@ -151,6 +151,66 @@ export class TweetRequests {
151
151
  };
152
152
  }
153
153
 
154
+ /**
155
+ * @param id - The id of the tweet whose edit history is to be fetched.
156
+ */
157
+ public static history(id: string): AxiosRequestConfig {
158
+ return {
159
+ method: 'get',
160
+ url: 'https://x.com/i/api/graphql/MGElmrYILE8wUfI8GorUYA/TweetEditHistory',
161
+ params: {
162
+ /* eslint-disable @typescript-eslint/naming-convention */
163
+ variables: JSON.stringify({
164
+ tweetId: id,
165
+ withQuickPromoteEligibilityTweetFields: true,
166
+ }),
167
+ features: JSON.stringify({
168
+ premium_content_api_read_enabled: false,
169
+ communities_web_enable_tweet_community_results_fetch: true,
170
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
171
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
172
+ responsive_web_grok_analyze_post_followups_enabled: true,
173
+ rweb_cashtags_composer_attachment_enabled: true,
174
+ responsive_web_jetfuel_frame: true,
175
+ responsive_web_grok_share_attachment_enabled: true,
176
+ responsive_web_grok_annotations_enabled: true,
177
+ freedom_of_speech_not_reach_fetch_enabled: true,
178
+ standardized_nudges_misinfo: true,
179
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
180
+ rweb_video_screen_enabled: false,
181
+ responsive_web_edit_tweet_api_enabled: true,
182
+ rweb_conversational_replies_downvote_enabled: false,
183
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
184
+ view_counts_everywhere_api_enabled: true,
185
+ longform_notetweets_consumption_enabled: true,
186
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
187
+ content_disclosure_indicator_enabled: true,
188
+ content_disclosure_ai_generated_indicator_enabled: true,
189
+ responsive_web_grok_show_grok_translated_post: true,
190
+ responsive_web_grok_analysis_button_from_backend: true,
191
+ post_ctas_fetch_enabled: true,
192
+ profile_label_improvements_pcf_label_in_post_enabled: true,
193
+ responsive_web_profile_redirect_enabled: false,
194
+ rweb_tipjar_consumption_enabled: false,
195
+ verified_phone_label_enabled: false,
196
+ rweb_cashtags_enabled: true,
197
+ longform_notetweets_rich_text_read_enabled: true,
198
+ longform_notetweets_inline_media_enabled: false,
199
+ articles_preview_enabled: true,
200
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
201
+ responsive_web_grok_community_note_auto_translation_is_enabled: true,
202
+ responsive_web_grok_image_annotation_enabled: true,
203
+ responsive_web_grok_imagine_annotation_enabled: true,
204
+ responsive_web_graphql_timeline_navigation_enabled: true,
205
+ creator_subscriptions_tweet_preview_api_enabled: true,
206
+ responsive_web_enhance_cards_enabled: false,
207
+ }),
208
+ /* eslint-enable @typescript-eslint/naming-convention */
209
+ },
210
+ paramsSerializer: { encode: encodeURIComponent },
211
+ };
212
+ }
213
+
154
214
  /**
155
215
  * @param id - The id of the tweet to be liked.
156
216
  */
@@ -980,6 +980,22 @@ export class UserRequests {
980
980
  };
981
981
  }
982
982
 
983
+ /**
984
+ * @param id - The id of the user to remove from the authenticated user's followers.
985
+ */
986
+ public static removeFollower(id: string): AxiosRequestConfig {
987
+ return {
988
+ method: 'post',
989
+ url: 'https://x.com/i/api/graphql/QpNfg0kpPRfjROQ_9eOLXA/RemoveFollower',
990
+ data: {
991
+ /* eslint-disable @typescript-eslint/naming-convention */
992
+ variables: { target_user_id: id },
993
+ queryId: 'QpNfg0kpPRfjROQ_9eOLXA',
994
+ /* eslint-enable @typescript-eslint/naming-convention */
995
+ },
996
+ };
997
+ }
998
+
983
999
  public static scheduled(): AxiosRequestConfig {
984
1000
  return {
985
1001
  method: 'get',