rettiwt-api 1.1.5 → 1.1.7

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 (122) hide show
  1. package/dist/graphql/enums/Errors.d.ts +1 -0
  2. package/dist/graphql/enums/Errors.js +1 -0
  3. package/dist/graphql/enums/Errors.js.map +1 -1
  4. package/dist/graphql/resolvers/UserResolver.d.ts +9 -0
  5. package/dist/graphql/resolvers/UserResolver.js +61 -0
  6. package/dist/graphql/resolvers/UserResolver.js.map +1 -1
  7. package/dist/graphql/types/UserTypes.js +1 -1
  8. package/dist/graphql/types/UserTypes.js.map +1 -1
  9. package/dist/requests/payloads/Variables.d.ts +23 -0
  10. package/dist/requests/payloads/Variables.js +24 -0
  11. package/dist/requests/payloads/Variables.js.map +1 -0
  12. package/dist/services/data/TweetService.d.ts +1 -1
  13. package/dist/services/data/TweetService.js +1 -1
  14. package/dist/services/data/TweetService.js.map +1 -1
  15. package/dist/services/data/UserService.d.ts +15 -0
  16. package/dist/services/data/UserService.js +33 -0
  17. package/dist/services/data/UserService.js.map +1 -1
  18. package/dist/services/helper/extractors/Users.d.ts +6 -0
  19. package/dist/services/helper/extractors/Users.js +53 -1
  20. package/dist/services/helper/extractors/Users.js.map +1 -1
  21. package/dist/services/helper/urls/Users.d.ts +8 -1
  22. package/dist/services/helper/urls/Users.js +12 -2
  23. package/dist/services/helper/urls/Users.js.map +1 -1
  24. package/dist/types/Query.d.ts +80 -0
  25. package/dist/types/Query.js +3 -0
  26. package/dist/types/Query.js.map +1 -0
  27. package/dist/types/raw/data/tweet/Favouriters.d.ts +164 -0
  28. package/dist/types/raw/data/tweet/Favouriters.js +3 -0
  29. package/dist/types/raw/data/tweet/Favouriters.js.map +1 -0
  30. package/dist/types/raw/data/tweet/Retweeters.d.ts +171 -0
  31. package/dist/types/raw/data/tweet/Retweeters.js +3 -0
  32. package/dist/types/raw/data/tweet/Retweeters.js.map +1 -0
  33. package/dist/types/raw/data/tweet/Tweet.d.ts +746 -0
  34. package/dist/types/raw/data/tweet/Tweet.js +3 -0
  35. package/dist/types/raw/data/tweet/Tweet.js.map +1 -0
  36. package/dist/types/raw/data/tweet/Tweets.d.ts +386 -0
  37. package/dist/types/raw/data/tweet/Tweets.js +3 -0
  38. package/dist/types/raw/data/tweet/Tweets.js.map +1 -0
  39. package/dist/types/raw/data/user/Followers.d.ts +176 -0
  40. package/dist/types/raw/data/user/Followers.js +3 -0
  41. package/dist/types/raw/data/user/Followers.js.map +1 -0
  42. package/dist/types/raw/data/user/Following.d.ts +176 -0
  43. package/dist/types/raw/data/user/Following.js +3 -0
  44. package/dist/types/raw/data/user/Following.js.map +1 -0
  45. package/dist/types/raw/data/user/Likes.d.ts +1059 -0
  46. package/dist/types/raw/data/user/Likes.js +3 -0
  47. package/dist/types/raw/data/user/Likes.js.map +1 -0
  48. package/dist/types/raw/data/user/User.d.ts +117 -0
  49. package/dist/types/raw/data/user/User.js +3 -0
  50. package/dist/types/raw/data/user/User.js.map +1 -0
  51. package/dist/types/raw/query/tweet/Details.d.ts +80 -0
  52. package/dist/types/raw/query/tweet/Details.js +5 -0
  53. package/dist/types/raw/query/tweet/Details.js.map +1 -0
  54. package/dist/types/raw/query/tweet/Engagements.d.ts +29 -0
  55. package/dist/types/raw/query/tweet/Engagements.js +3 -0
  56. package/dist/types/raw/query/tweet/Engagements.js.map +1 -0
  57. package/dist/types/raw/query/tweet/Likes.d.ts +29 -0
  58. package/dist/types/raw/query/tweet/Likes.js +3 -0
  59. package/dist/types/raw/query/tweet/Likes.js.map +1 -0
  60. package/dist/types/raw/query/tweet/Retweets.d.ts +29 -0
  61. package/dist/types/raw/query/tweet/Retweets.js +3 -0
  62. package/dist/types/raw/query/tweet/Retweets.js.map +1 -0
  63. package/dist/types/raw/query/tweet/Search.d.ts +40 -0
  64. package/dist/types/raw/query/tweet/Search.js +3 -0
  65. package/dist/types/raw/query/tweet/Search.js.map +1 -0
  66. package/dist/types/raw/query/tweet/TweetLike.d.ts +29 -0
  67. package/dist/types/raw/query/tweet/TweetLike.js +3 -0
  68. package/dist/types/raw/query/tweet/TweetLike.js.map +1 -0
  69. package/dist/types/raw/query/tweet/TweetLikes.d.ts +29 -0
  70. package/dist/types/raw/query/tweet/TweetLikes.js +3 -0
  71. package/dist/types/raw/query/tweet/TweetLikes.js.map +1 -0
  72. package/dist/types/raw/query/tweet/TweetRetweets.d.ts +0 -0
  73. package/dist/types/raw/query/tweet/TweetRetweets.js +2 -0
  74. package/dist/types/raw/query/tweet/TweetRetweets.js.map +1 -0
  75. package/dist/types/raw/query/user/Details.d.ts +34 -0
  76. package/dist/types/raw/query/user/Details.js +3 -0
  77. package/dist/types/raw/query/user/Details.js.map +1 -0
  78. package/dist/types/raw/user/Tweets.d.ts +668 -1584
  79. package/dist/types/raw/user/User.js.map +1 -1
  80. package/package.json +2 -2
  81. package/src/graphql/enums/Errors.ts +1 -0
  82. package/src/graphql/resolvers/UserResolver.ts +58 -1
  83. package/src/graphql/types/UserTypes.ts +3 -3
  84. package/src/services/data/TweetService.ts +5 -5
  85. package/src/services/data/UserService.ts +34 -0
  86. package/src/services/helper/extractors/Users.ts +55 -0
  87. package/src/services/helper/urls/Users.ts +39 -23
  88. package/src/types/raw/user/Tweets.ts +1747 -0
  89. package/docs/.nojekyll +0 -1
  90. package/docs/assets/highlight.css +0 -64
  91. package/docs/assets/main.js +0 -58
  92. package/docs/assets/search.js +0 -1
  93. package/docs/assets/style.css +0 -1280
  94. package/docs/classes/AccountService.html +0 -303
  95. package/docs/classes/AuthCookie.html +0 -146
  96. package/docs/classes/AuthService.html +0 -147
  97. package/docs/classes/CacheService.html +0 -157
  98. package/docs/classes/Cursor.html +0 -102
  99. package/docs/classes/CursoredData.html +0 -126
  100. package/docs/classes/DataValidationError.html +0 -119
  101. package/docs/classes/FetcherService.html +0 -225
  102. package/docs/classes/Tweet.html +0 -210
  103. package/docs/classes/TweetEntities.html +0 -128
  104. package/docs/classes/TweetFilter.html +0 -204
  105. package/docs/classes/TweetListArgs.html +0 -118
  106. package/docs/classes/TweetService.html +0 -313
  107. package/docs/classes/User.html +0 -230
  108. package/docs/classes/UserListArgs.html +0 -118
  109. package/docs/classes/UserService.html +0 -315
  110. package/docs/enums/HttpMethods.html +0 -74
  111. package/docs/functions/Rettiwt.html +0 -99
  112. package/docs/index.html +0 -161
  113. package/docs/interfaces/IAuthCookie.html +0 -104
  114. package/docs/interfaces/ICursor.html +0 -77
  115. package/docs/interfaces/ICursoredData.html +0 -93
  116. package/docs/interfaces/IDataContext.html +0 -91
  117. package/docs/interfaces/IListArgs.html +0 -87
  118. package/docs/interfaces/ITweet.html +0 -176
  119. package/docs/interfaces/ITweetEntities.html +0 -104
  120. package/docs/interfaces/ITweetFilter.html +0 -158
  121. package/docs/interfaces/IUser.html +0 -194
  122. package/docs/modules.html +0 -109
@@ -1 +1 @@
1
- {"version":3,"file":"User.js","sourceRoot":"","sources":["../../../../src/types/raw/User/User.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"User.js","sourceRoot":"","sources":["../../../../src/types/raw/user/User.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rettiwt-api",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "description": "An API for fetching data from TwitterAPI, without any rate limits!",
@@ -43,4 +43,4 @@
43
43
  "typedoc": "0.23.26",
44
44
  "typescript": "4.6.4"
45
45
  }
46
- }
46
+ }
@@ -16,6 +16,7 @@ export enum DataErrors {
16
16
  NoTweetsFound = "No tweets matching the given criteria found",
17
17
  NoLikersFound = "No likers found for the tweet with the given id",
18
18
  NoRetweetersFound = "No retweeters found for the tweet with the given id",
19
+ NoUserTweetsFound = "No tweets were found for the user with the given id",
19
20
  NoFollowsFound = "No follow details were found for the user with the given id",
20
21
  NoLikedTweetsFound = "No liked tweets were found for the user with the given id"
21
22
  };
@@ -9,7 +9,7 @@ import { DataErrors } from '../enums/Errors';
9
9
  export default class UserResolver extends ResolverBase {
10
10
  // MEMBER DATA
11
11
  private batchSize: number; // To store the batch size when fetching data
12
-
12
+
13
13
  // MEMBER METHODS
14
14
  constructor(context: IDataContext) {
15
15
  super(context);
@@ -27,6 +27,63 @@ export default class UserResolver extends ResolverBase {
27
27
  });
28
28
  }
29
29
 
30
+ /**
31
+ * @returns The list of tweets made by the given user
32
+ * @param id The id of the user whose tweets are to be fetched
33
+ * @param count The number of tweets to fetch, must be >= 40
34
+ * @param all Whether to fetch list of all tweets made by user
35
+ * @param cursor The cursor to the batch of tweets to fetch
36
+ * @param statusesCount The total number of tweets made by target user
37
+ */
38
+ async resolveUserTweets(id: string, count: number, all: boolean, cursor: string, statusesCount: number): Promise<any> {
39
+ let likes: any[] = []; // To store the list of tweets
40
+ let next: Cursor = new Cursor(cursor); // To store cursor to next batch
41
+ let total: number = 0; // To store the total number of tweets fetched
42
+
43
+ // If all tweets are to be fetched
44
+ count = all ? statusesCount : count;
45
+
46
+ // If required count less than batch size, setting batch size to required count
47
+ this.batchSize = (count < this.batchSize) ? count : this.batchSize;
48
+
49
+ // Repeatedly fetching data as long as total data fetched is less than requried
50
+ do {
51
+ // If this is the last batch, change batch size to number of remaining tweets
52
+ this.batchSize = ((count - total) < this.batchSize) ? (count - total) : this.batchSize;
53
+
54
+ // Getting the data
55
+ const res = await this.context.users.getUserTweets(id, this.batchSize, next.value).catch(error => {
56
+ throw this.getGraphQLError(error);
57
+ });
58
+
59
+ // If data is available
60
+ if (res.list?.length) {
61
+ // Adding fetched tweets to list of tweets
62
+ likes = likes.concat(res.list);
63
+
64
+ // Updating total tweets fetched
65
+ total = likes.length;
66
+
67
+ // Getting cursor to next batch
68
+ next = res.next as Cursor;
69
+ }
70
+ // If no more data is available
71
+ else {
72
+ break;
73
+ }
74
+ } while (total < count);
75
+
76
+ // If no likes found
77
+ if (!likes.length) {
78
+ return new Error(DataErrors.NoUserTweetsFound);
79
+ }
80
+
81
+ // Adding the cursor to the end of list of data
82
+ likes.push(next);
83
+
84
+ return likes;
85
+ }
86
+
30
87
  /**
31
88
  * @returns The list of tweets liked by the given user
32
89
  * @param id The id of the user whose likes are to be fetched
@@ -113,7 +113,7 @@ export const User: GraphQLObjectType = new GraphQLObjectType({
113
113
  defaultValue: ''
114
114
  }
115
115
  },
116
- resolve: (parent, args, context) => new TweetResolver(context).resolveTweets({ fromUsers: [parent.userName] } as TweetFilter, args.all ? parent.statusesCount : args.count, args.cursor)
116
+ resolve: (parent, args, context) => new UserResolver(context).resolveUserTweets(parent.id, args.count, args.all, args.cursor, parent.statusesCount)
117
117
  }
118
118
  })
119
119
  });
@@ -124,11 +124,11 @@ export const UserList: GraphQLList<GraphQLType> = new GraphQLList(new GraphQLUni
124
124
  types: [User, Cursor],
125
125
  resolveType: (data) => {
126
126
  // If it has a userName field => this is a User object
127
- if(data.userName) {
127
+ if (data.userName) {
128
128
  return User;
129
129
  }
130
130
  // If it has a value field => this is a Cursor object
131
- else if(data.value) {
131
+ else if (data.value) {
132
132
  return Cursor;
133
133
  }
134
134
  }
@@ -51,7 +51,7 @@ export class TweetService extends FetcherService {
51
51
  *
52
52
  * @remarks
53
53
  *
54
- * If cookies have been provided, then authenticated requests are made. Else, guest requests are made.
54
+ * Cookies are required to use this method!
55
55
  */
56
56
  async getTweets(query: TweetFilter, count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
57
57
  // Objectifying parameters
@@ -95,7 +95,7 @@ export class TweetService extends FetcherService {
95
95
  if (cachedData) {
96
96
  return cachedData;
97
97
  }
98
-
98
+
99
99
  // Fetching the raw data
100
100
  let res = await this.request<RawTweet>(TweetUrls.tweetDetailsUrl(id), false).then(res => res.data);
101
101
 
@@ -128,13 +128,13 @@ export class TweetService extends FetcherService {
128
128
  */
129
129
  async getTweetLikers(tweetId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
130
130
  // If user is not authenticated, abort
131
- if(!this.isAuthenticated) {
131
+ if (!this.isAuthenticated) {
132
132
  throw new Error(AuthenticationErrors.NotAuthenticated);
133
133
  }
134
134
 
135
135
  // Objectifying parameters
136
136
  let args: TweetListArgs = new TweetListArgs(count, cursor);
137
-
137
+
138
138
  // Fetching the raw data
139
139
  let res = await this.request<RawLikers>(TweetUrls.tweetLikesUrl(tweetId, args.count, args.cursor)).then(res => res.data);
140
140
 
@@ -167,7 +167,7 @@ export class TweetService extends FetcherService {
167
167
  */
168
168
  async getTweetRetweeters(tweetId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
169
169
  // If user is not authenticated, abort
170
- if(!this.isAuthenticated) {
170
+ if (!this.isAuthenticated) {
171
171
  throw new Error(AuthenticationErrors.NotAuthenticated);
172
172
  }
173
173
 
@@ -11,6 +11,7 @@ import { Tweet } from '../../models/data/Tweet';
11
11
  import { CursoredData } from '../../models/data/CursoredData';
12
12
  import { Result as TweetData } from '../../types/raw/tweet/Tweet';
13
13
  import RawUser, { Result as UserData } from '../../types/raw/user/User';
14
+ import RawUserTweets from '../../types/raw/user/Tweets';
14
15
  import RawUserFollowers from '../../types/raw/user/Followers';
15
16
  import RawUserFollowing from '../../types/raw/user/Following';
16
17
  import RawUserLikes from '../../types/raw/user/Likes';
@@ -80,6 +81,39 @@ export class UserService extends FetcherService {
80
81
  return user;
81
82
  }
82
83
 
84
+ /**
85
+ * @param userId The rest id of the target user.
86
+ * @param count The number of tweets to fetch, must be >= 40 (when no cursor is provided) and <=100.
87
+ * @param cursor The cursor to next batch. If blank, first batch is fetched.
88
+ *
89
+ * @returns The list of tweets nade by the target user.
90
+ *
91
+ * @throws {@link Errors.ValidationErrors.InvalidCount} error, if invalid count has been provided.
92
+ * @throws {@link Errors.DataErrors.UserNotFound} error, if invalid count has been provided.
93
+ *
94
+ * @remarks
95
+ *
96
+ * No cookies are required to use this method.
97
+ */
98
+ async getUserTweets(userId: string, count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
99
+ // Objectifying parameters
100
+ let args: UserListArgs = new UserListArgs(count, cursor);
101
+
102
+ // Fetching the raw data
103
+ let res = await this.request<RawUserTweets>(UserUrls.userTweetsUrl(userId, args.count, args.cursor), false).then(res => res.data);
104
+
105
+ // Extracting data
106
+ let data = UserExtractors.extractUserTweets(res);
107
+
108
+ // Caching data
109
+ this.cacheData(data);
110
+
111
+ // Parsing data
112
+ let tweets = data.required.map((item: TweetData) => new Tweet(item));
113
+
114
+ return new CursoredData<Tweet>(tweets, data.cursor);
115
+ }
116
+
83
117
  /**
84
118
  * @param userId The rest id of the target user.
85
119
  * @param count The number of following to fetch, must be >= 40 (when no cursor is provided) and <=100.
@@ -2,6 +2,7 @@
2
2
  import { IDataExtract } from '../../../types/Resolvers'
3
3
  import { DataErrors } from '../../../enums/Errors';
4
4
  import RawUser from '../../../types/raw/user/User';
5
+ import RawUserTweets from '../../../types/raw/user/Tweets';
5
6
  import RawUserFollowers from '../../../types/raw/user/Followers';
6
7
  import RawUserFollowing from '../../../types/raw/user/Following';
7
8
  import RawUserLikes from '../../../types/raw/user/Likes';
@@ -37,6 +38,60 @@ export function extractUserDetails(res: RawUser): IDataExtract {
37
38
  };
38
39
  }
39
40
 
41
+ /**
42
+ * @returns The raw user tweet data formatted and sorted into required and additional data
43
+ * @param res The raw response received from Twitter
44
+ */
45
+ export function extractUserTweets(res: RawUserTweets): IDataExtract {
46
+ let required: any[] = []; // To store the reqruied raw data
47
+ let cursor: string = ''; // To store the cursor to next batch
48
+ let users: any[] = []; // To store additional user data
49
+ let tweets: any[] = []; // To store additional tweet data
50
+
51
+ // If user does not exist
52
+ if (Parsers.isJSONEmpty(res.data.user)) {
53
+ throw new Error(DataErrors.UserNotFound);
54
+ }
55
+
56
+ // Extracting the raw list
57
+ res.data.user.result.timeline_v2.timeline.instructions.forEach(item => {
58
+ if (item.type === 'TimelineAddEntries') {
59
+ // If no tweets found
60
+ if (item.entries?.length == 2) {
61
+ // Returning the data
62
+ return {
63
+ required: required,
64
+ cursor: cursor,
65
+ users: users,
66
+ tweets: tweets
67
+ };
68
+ }
69
+
70
+ // Destructuring data
71
+ item.entries.forEach(entry => {
72
+ // If entry is of type tweet and tweet exists
73
+ if (entry.entryId.indexOf('tweet') != -1 && entry.content.itemContent?.tweet_results.result.__typename === 'Tweet') {
74
+ required.push(entry.content.itemContent.tweet_results.result);
75
+ users.push(entry.content.itemContent.tweet_results.result.core.user_results.result);
76
+ tweets.push(entry.content.itemContent.tweet_results.result);
77
+ }
78
+ // If entry is of type cursor
79
+ else if (entry.entryId.indexOf('cursor-bottom') != -1) {
80
+ cursor = entry.content.value ?? '';
81
+ }
82
+ });
83
+ }
84
+ });
85
+
86
+ // Returning the data
87
+ return {
88
+ required: required,
89
+ cursor: cursor,
90
+ users: users,
91
+ tweets: tweets
92
+ };
93
+ }
94
+
40
95
  /**
41
96
  * @returns The raw user following/followers data formatted and sorted into required and additional data
42
97
  * @param res The raw response received from TwitterAPI
@@ -3,7 +3,7 @@
3
3
  * @param screenName The screen name of the target user
4
4
  */
5
5
  export function userDetailsUrl(screenName: string): string {
6
- return `https://api.twitter.com/graphql/hVhfo_TquFTmgL7gYwf91Q/UserByScreenName?variables=%7B%22screen_name%22%3A%22${screenName}%22%2C%22withSafetyModeUserFields%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%7D`
6
+ return `https://api.twitter.com/graphql/hVhfo_TquFTmgL7gYwf91Q/UserByScreenName?variables=%7B%22screen_name%22%3A%22${screenName}%22%2C%22withSafetyModeUserFields%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%7D`;
7
7
  }
8
8
 
9
9
  /**
@@ -11,23 +11,35 @@ export function userDetailsUrl(screenName: string): string {
11
11
  * @param restid The restId of the target user
12
12
  */
13
13
  export function userDetailsByIdUrl(restId: string): string {
14
- return `https://api.twitter.com/graphql/mi_IjXgFyr41N9zkszPz9w/UserByRestId?variables=%7B%22userId%22%3A%22${restId}%22%2C%22withSafetyModeUserFields%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%7D`;
14
+ return `https://api.twitter.com/graphql/mi_IjXgFyr41N9zkszPz9w/UserByRestId?variables=%7B%22userId%22%3A%22${restId}%22%2C%22withSafetyModeUserFields%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%7D`;
15
15
  }
16
16
 
17
17
  /**
18
- * @returns The url for fetching the list of users followed bu target user.
18
+ * @returns The url for fetching the list of tweet made by target user.
19
+ * @param userId The rest id of the target user
20
+ * @param count The batch size of the list of tweets, should be >= 40 and <=100
21
+ * @param cursor The cursor to next batch
22
+ */
23
+ export function userTweetsUrl(userId: string, count: number, cursor: string): string {
24
+ return `https://api.twitter.com/graphql/xxLjoOBBPpYBHbBTI-hevQ/UserTweetsAndReplies?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${cursor}%22%2C%22includePromotedContent%22%3Atrue%2C%22withCommunity%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
25
+ }
26
+
27
+ /**
28
+ * @returns The url for fetching the list of users followed by target user.
19
29
  * @param userId The rest id of the target user
20
30
  * @param count The batch size of the list of following, should be >= 40 and <=100
21
31
  * @param cursor The cursor to next batch
22
32
  */
23
33
  export function userFollowingUrl(userId: string, count: number, cursor: string): string {
24
- /**
25
- * Twitter has a ver odd behaviour here.
26
- * If no cursor is provided, the number of followings fetched is slightly more the given count.
27
- * If a cursor if provided, the number of followings is sometimes less than the provided count.
28
- * NO SOLUTION EXISTS AS OF NOW!
29
- */
30
- return `https://api.twitter.com/graphql/mSnjZc5CTm2Z5Lu_i4XsPQ/Following?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${encodeURIComponent(cursor)}%22%2C%22includePromotedContent%22%3Afalse%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_uc_gql_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
34
+ /**
35
+ * Twitter has a ver odd behaviour here.
36
+ * If no cursor is provided, the number of followings fetched is slightly more the given count.
37
+ * If a cursor if provided, the number of followings is sometimes less than the provided count.
38
+ * NO SOLUTION EXISTS AS OF NOW!
39
+ */
40
+ return `https://api.twitter.com/graphql/mSnjZc5CTm2Z5Lu_i4XsPQ/Following?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${encodeURIComponent(
41
+ cursor,
42
+ )}%22%2C%22includePromotedContent%22%3Afalse%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_uc_gql_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
31
43
  }
32
44
 
33
45
  /**
@@ -37,18 +49,20 @@ export function userFollowingUrl(userId: string, count: number, cursor: string):
37
49
  * @param cursor The cusor to next batch
38
50
  */
39
51
  export function userFollowersUrl(userId: string, count: number, cursor: string): string {
40
- /**
41
- * Twitter has a very odd behaviour here.
42
- * If no cursor is provided, the number of followers fetched is equal to count + 20.
43
- * If a cursor is provided, the number of followers fetched is equal to count.
44
- * The solution is to check accordingly, if a cursor if provided or not and manipulate the count
45
- */
46
- // If no cursor if provided
47
- if (!cursor) {
48
- count = count - 20;
49
- }
52
+ /**
53
+ * Twitter has a very odd behaviour here.
54
+ * If no cursor is provided, the number of followers fetched is equal to count + 20.
55
+ * If a cursor is provided, the number of followers fetched is equal to count.
56
+ * The solution is to check accordingly, if a cursor if provided or not and manipulate the count
57
+ */
58
+ // If no cursor if provided
59
+ if (!cursor) {
60
+ count = count - 20;
61
+ }
50
62
 
51
- return `https://api.twitter.com/graphql/nwlAnaw7oKXcVLi91ehy7Q/Followers?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${encodeURIComponent(cursor)}%22%2C%22includePromotedContent%22%3Afalse%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_uc_gql_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
63
+ return `https://api.twitter.com/graphql/nwlAnaw7oKXcVLi91ehy7Q/Followers?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${encodeURIComponent(
64
+ cursor,
65
+ )}%22%2C%22includePromotedContent%22%3Afalse%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_uc_gql_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
52
66
  }
53
67
 
54
68
  /**
@@ -58,5 +72,7 @@ export function userFollowersUrl(userId: string, count: number, cursor: string):
58
72
  * @param cursor The cusor to next batch
59
73
  */
60
74
  export function userLikesUrl(userId: string, count: number, cursor: string): string {
61
- return `https://api.twitter.com/graphql/gP4ZKghLd4tpILgS6VudAQ/Likes?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${encodeURIComponent(cursor)}%22%2C%22includePromotedContent%22%3Afalse%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%2C%22withClientEventToken%22%3Afalse%2C%22withBirdwatchNotes%22%3Afalse%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_uc_gql_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
62
- }
75
+ return `https://api.twitter.com/graphql/gP4ZKghLd4tpILgS6VudAQ/Likes?variables=%7B%22userId%22%3A%22${userId}%22%2C%22count%22%3A${count}%2C%22cursor%22%3A%22${encodeURIComponent(
76
+ cursor,
77
+ )}%22%2C%22includePromotedContent%22%3Afalse%2C%22withSuperFollowsUserFields%22%3Atrue%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%2C%22withSuperFollowsTweetFields%22%3Atrue%2C%22withClientEventToken%22%3Afalse%2C%22withBirdwatchNotes%22%3Afalse%2C%22withVoice%22%3Atrue%2C%22withV2Timeline%22%3Atrue%7D&features=%7B%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22view_counts_public_visibility_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22responsive_web_uc_gql_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D`;
78
+ }