rettiwt-api 1.4.0 → 2.0.1

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 (232) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.js +54 -0
  3. package/.github/workflows/documentation.yml +29 -9
  4. package/.github/workflows/publish.yml +8 -3
  5. package/.prettierignore +3 -0
  6. package/.prettierrc +13 -0
  7. package/README.md +59 -61
  8. package/dist/Rettiwt.d.ts +19 -0
  9. package/dist/Rettiwt.js +30 -0
  10. package/dist/Rettiwt.js.map +1 -0
  11. package/dist/enums/ApiErrors.d.ts +30 -0
  12. package/dist/enums/ApiErrors.js +35 -0
  13. package/dist/enums/ApiErrors.js.map +1 -0
  14. package/dist/enums/HTTP.d.ts +11 -11
  15. package/dist/enums/HTTP.js +15 -16
  16. package/dist/enums/HTTP.js.map +1 -1
  17. package/dist/helper/JsonUtils.d.ts +26 -0
  18. package/dist/helper/JsonUtils.js +88 -0
  19. package/dist/helper/JsonUtils.js.map +1 -0
  20. package/dist/index.d.ts +10 -43
  21. package/dist/index.js +16 -55
  22. package/dist/index.js.map +1 -1
  23. package/dist/models/CursoredData.d.ts +37 -0
  24. package/dist/models/CursoredData.js +59 -0
  25. package/dist/models/CursoredData.js.map +1 -0
  26. package/dist/models/{data/Tweet.d.ts → Tweet.d.ts} +4 -4
  27. package/dist/models/{data/Tweet.js → Tweet.js} +7 -32
  28. package/dist/models/Tweet.js.map +1 -0
  29. package/dist/models/{data/User.d.ts → User.d.ts} +3 -3
  30. package/dist/models/{data/User.js → User.js} +3 -3
  31. package/dist/models/User.js.map +1 -0
  32. package/dist/services/FetcherService.d.ts +66 -0
  33. package/dist/services/FetcherService.js +209 -0
  34. package/dist/services/FetcherService.js.map +1 -0
  35. package/dist/services/TweetService.d.ts +88 -0
  36. package/dist/services/TweetService.js +244 -0
  37. package/dist/services/TweetService.js.map +1 -0
  38. package/dist/services/UserService.d.ts +60 -0
  39. package/dist/services/UserService.js +188 -0
  40. package/dist/services/UserService.js.map +1 -0
  41. package/dist/types/{Service.d.ts → CursoredData.d.ts} +3 -3
  42. package/dist/types/CursoredData.js +3 -0
  43. package/dist/types/CursoredData.js.map +1 -0
  44. package/dist/types/Tweet.js +1 -1
  45. package/dist/types/User.js +1 -1
  46. package/package.json +15 -19
  47. package/src/Rettiwt.ts +33 -0
  48. package/src/enums/ApiErrors.ts +30 -0
  49. package/src/enums/HTTP.ts +12 -12
  50. package/src/helper/JsonUtils.ts +86 -0
  51. package/src/index.ts +14 -57
  52. package/src/models/CursoredData.ts +64 -0
  53. package/src/models/Tweet.ts +116 -0
  54. package/src/models/User.ts +72 -0
  55. package/src/services/FetcherService.ts +186 -0
  56. package/src/services/TweetService.ts +153 -0
  57. package/src/services/UserService.ts +117 -0
  58. package/src/types/CursoredData.ts +24 -0
  59. package/src/types/Tweet.ts +35 -35
  60. package/src/types/User.ts +30 -30
  61. package/tsconfig.json +9 -9
  62. package/dist/config/env.d.ts +0 -5
  63. package/dist/config/env.js +0 -9
  64. package/dist/config/env.js.map +0 -1
  65. package/dist/enums/Errors.d.ts +0 -21
  66. package/dist/enums/Errors.js +0 -29
  67. package/dist/enums/Errors.js.map +0 -1
  68. package/dist/graphql/enums/Errors.d.ts +0 -21
  69. package/dist/graphql/enums/Errors.js +0 -29
  70. package/dist/graphql/enums/Errors.js.map +0 -1
  71. package/dist/graphql/queries/RootQuery.d.ts +0 -4
  72. package/dist/graphql/queries/RootQuery.js +0 -83
  73. package/dist/graphql/queries/RootQuery.js.map +0 -1
  74. package/dist/graphql/resolvers/AccountResolver.d.ts +0 -12
  75. package/dist/graphql/resolvers/AccountResolver.js +0 -84
  76. package/dist/graphql/resolvers/AccountResolver.js.map +0 -1
  77. package/dist/graphql/resolvers/ResolverBase.d.ts +0 -16
  78. package/dist/graphql/resolvers/ResolverBase.js +0 -23
  79. package/dist/graphql/resolvers/ResolverBase.js.map +0 -1
  80. package/dist/graphql/resolvers/TweetResolver.d.ts +0 -46
  81. package/dist/graphql/resolvers/TweetResolver.js +0 -302
  82. package/dist/graphql/resolvers/TweetResolver.js.map +0 -1
  83. package/dist/graphql/resolvers/UserResolver.d.ts +0 -48
  84. package/dist/graphql/resolvers/UserResolver.js +0 -334
  85. package/dist/graphql/resolvers/UserResolver.js.map +0 -1
  86. package/dist/graphql/types/Global.d.ts +0 -4
  87. package/dist/graphql/types/Global.js +0 -13
  88. package/dist/graphql/types/Global.js.map +0 -1
  89. package/dist/graphql/types/TweetTypes.d.ts +0 -4
  90. package/dist/graphql/types/TweetTypes.js +0 -160
  91. package/dist/graphql/types/TweetTypes.js.map +0 -1
  92. package/dist/graphql/types/UserTypes.d.ts +0 -3
  93. package/dist/graphql/types/UserTypes.js +0 -137
  94. package/dist/graphql/types/UserTypes.js.map +0 -1
  95. package/dist/models/args/TweetListArgs.d.ts +0 -21
  96. package/dist/models/args/TweetListArgs.js +0 -54
  97. package/dist/models/args/TweetListArgs.js.map +0 -1
  98. package/dist/models/args/UserListArgs.d.ts +0 -21
  99. package/dist/models/args/UserListArgs.js +0 -54
  100. package/dist/models/args/UserListArgs.js.map +0 -1
  101. package/dist/models/auth/AuthCookie.d.ts +0 -21
  102. package/dist/models/auth/AuthCookie.js +0 -33
  103. package/dist/models/auth/AuthCookie.js.map +0 -1
  104. package/dist/models/data/CursoredData.d.ts +0 -34
  105. package/dist/models/data/CursoredData.js +0 -42
  106. package/dist/models/data/CursoredData.js.map +0 -1
  107. package/dist/models/data/Tweet.js.map +0 -1
  108. package/dist/models/data/User.js.map +0 -1
  109. package/dist/server.d.ts +0 -1
  110. package/dist/server.js +0 -76
  111. package/dist/server.js.map +0 -1
  112. package/dist/services/auth/AccountService.d.ts +0 -83
  113. package/dist/services/auth/AccountService.js +0 -412
  114. package/dist/services/auth/AccountService.js.map +0 -1
  115. package/dist/services/auth/AuthService.d.ts +0 -31
  116. package/dist/services/auth/AuthService.js +0 -118
  117. package/dist/services/auth/AuthService.js.map +0 -1
  118. package/dist/services/data/TweetService.d.ts +0 -60
  119. package/dist/services/data/TweetService.js +0 -250
  120. package/dist/services/data/TweetService.js.map +0 -1
  121. package/dist/services/data/UserService.d.ts +0 -71
  122. package/dist/services/data/UserService.js +0 -278
  123. package/dist/services/data/UserService.js.map +0 -1
  124. package/dist/services/helper/Headers.d.ts +0 -19
  125. package/dist/services/helper/Headers.js +0 -62
  126. package/dist/services/helper/Headers.js.map +0 -1
  127. package/dist/services/helper/Parser.d.ts +0 -22
  128. package/dist/services/helper/Parser.js +0 -84
  129. package/dist/services/helper/Parser.js.map +0 -1
  130. package/dist/services/helper/extractors/Tweets.d.ts +0 -23
  131. package/dist/services/helper/extractors/Tweets.js +0 -200
  132. package/dist/services/helper/extractors/Tweets.js.map +0 -1
  133. package/dist/services/helper/extractors/Users.d.ts +0 -17
  134. package/dist/services/helper/extractors/Users.js +0 -151
  135. package/dist/services/helper/extractors/Users.js.map +0 -1
  136. package/dist/services/helper/payloads/LoginFlows.d.ts +0 -77
  137. package/dist/services/helper/payloads/LoginFlows.js +0 -92
  138. package/dist/services/helper/payloads/LoginFlows.js.map +0 -1
  139. package/dist/services/helper/urls/Authentication.d.ts +0 -4
  140. package/dist/services/helper/urls/Authentication.js +0 -11
  141. package/dist/services/helper/urls/Authentication.js.map +0 -1
  142. package/dist/services/util/CacheService.d.ts +0 -33
  143. package/dist/services/util/CacheService.js +0 -96
  144. package/dist/services/util/CacheService.js.map +0 -1
  145. package/dist/services/util/FetcherService.d.ts +0 -65
  146. package/dist/services/util/FetcherService.js +0 -202
  147. package/dist/services/util/FetcherService.js.map +0 -1
  148. package/dist/types/Args.d.ts +0 -11
  149. package/dist/types/Args.js +0 -4
  150. package/dist/types/Args.js.map +0 -1
  151. package/dist/types/Authentication.d.ts +0 -55
  152. package/dist/types/Authentication.js +0 -6
  153. package/dist/types/Authentication.js.map +0 -1
  154. package/dist/types/Resolvers.d.ts +0 -15
  155. package/dist/types/Resolvers.js +0 -3
  156. package/dist/types/Resolvers.js.map +0 -1
  157. package/dist/types/Rettiwt.d.ts +0 -16
  158. package/dist/types/Rettiwt.js +0 -3
  159. package/dist/types/Rettiwt.js.map +0 -1
  160. package/dist/types/Service.js +0 -5
  161. package/dist/types/Service.js.map +0 -1
  162. package/docs/.nojekyll +0 -1
  163. package/docs/assets/highlight.css +0 -64
  164. package/docs/assets/main.js +0 -58
  165. package/docs/assets/search.js +0 -1
  166. package/docs/assets/style.css +0 -1280
  167. package/docs/classes/AccountService.html +0 -286
  168. package/docs/classes/AuthCookie.html +0 -146
  169. package/docs/classes/AuthService.html +0 -147
  170. package/docs/classes/CacheService.html +0 -157
  171. package/docs/classes/Cursor.html +0 -102
  172. package/docs/classes/CursoredData.html +0 -126
  173. package/docs/classes/DataValidationError.html +0 -120
  174. package/docs/classes/FetcherService.html +0 -225
  175. package/docs/classes/Tweet.html +0 -210
  176. package/docs/classes/TweetEntities.html +0 -128
  177. package/docs/classes/TweetFilter.html +0 -233
  178. package/docs/classes/TweetListArgs.html +0 -118
  179. package/docs/classes/TweetService.html +0 -319
  180. package/docs/classes/User.html +0 -230
  181. package/docs/classes/UserListArgs.html +0 -118
  182. package/docs/classes/UserService.html +0 -355
  183. package/docs/enums/HttpMethods.html +0 -74
  184. package/docs/functions/Rettiwt.html +0 -100
  185. package/docs/index.html +0 -159
  186. package/docs/interfaces/IAuthCookie.html +0 -104
  187. package/docs/interfaces/ICursor.html +0 -77
  188. package/docs/interfaces/ICursoredData.html +0 -93
  189. package/docs/interfaces/IDataContext.html +0 -91
  190. package/docs/interfaces/IDataValidationError.html +0 -109
  191. package/docs/interfaces/IListArgs.html +0 -87
  192. package/docs/interfaces/ITweet.html +0 -176
  193. package/docs/interfaces/ITweetEntities.html +0 -104
  194. package/docs/interfaces/ITweetFilter.html +0 -158
  195. package/docs/interfaces/IUser.html +0 -194
  196. package/docs/modules.html +0 -111
  197. package/environment.d.ts +0 -11
  198. package/src/config/env.ts +0 -5
  199. package/src/enums/Errors.ts +0 -22
  200. package/src/graphql/enums/Errors.ts +0 -22
  201. package/src/graphql/queries/RootQuery.ts +0 -81
  202. package/src/graphql/resolvers/AccountResolver.ts +0 -22
  203. package/src/graphql/resolvers/ResolverBase.ts +0 -26
  204. package/src/graphql/resolvers/TweetResolver.ts +0 -225
  205. package/src/graphql/resolvers/UserResolver.ts +0 -257
  206. package/src/graphql/types/Global.ts +0 -10
  207. package/src/graphql/types/TweetTypes.ts +0 -158
  208. package/src/graphql/types/UserTypes.ts +0 -134
  209. package/src/models/args/TweetListArgs.ts +0 -47
  210. package/src/models/args/UserListArgs.ts +0 -47
  211. package/src/models/auth/AuthCookie.ts +0 -43
  212. package/src/models/data/CursoredData.ts +0 -45
  213. package/src/models/data/Tweet.ts +0 -118
  214. package/src/models/data/User.ts +0 -72
  215. package/src/server.ts +0 -37
  216. package/src/services/auth/AccountService.ts +0 -283
  217. package/src/services/auth/AuthService.ts +0 -81
  218. package/src/services/data/TweetService.ts +0 -197
  219. package/src/services/data/UserService.ts +0 -221
  220. package/src/services/helper/Headers.ts +0 -60
  221. package/src/services/helper/Parser.ts +0 -89
  222. package/src/services/helper/extractors/Tweets.ts +0 -190
  223. package/src/services/helper/extractors/Users.ts +0 -141
  224. package/src/services/helper/payloads/LoginFlows.ts +0 -90
  225. package/src/services/helper/urls/Authentication.ts +0 -6
  226. package/src/services/util/CacheService.ts +0 -76
  227. package/src/services/util/FetcherService.ts +0 -143
  228. package/src/types/Args.ts +0 -12
  229. package/src/types/Authentication.ts +0 -63
  230. package/src/types/Resolvers.ts +0 -18
  231. package/src/types/Rettiwt.ts +0 -20
  232. package/src/types/Service.ts +0 -24
@@ -0,0 +1,116 @@
1
+ // TYPES
2
+ import { ITweet, ITweetEntities } from '../types/Tweet';
3
+ import { ITweet as IRawTweet, IEntities as IRawTweetEntities } from 'rettiwt-core';
4
+
5
+ // PARSERS
6
+ import { normalizeText } from '../helper/JsonUtils';
7
+
8
+ /**
9
+ * The different types parsed entities like urls, media, mentions, hashtags, etc.
10
+ *
11
+ * @public
12
+ */
13
+ export class TweetEntities implements ITweetEntities {
14
+ /** The list of hashtags mentioned in the tweet. */
15
+ hashtags: string[] = [];
16
+
17
+ /** The list of urls mentioned in the tweet. */
18
+ urls: string[] = [];
19
+
20
+ /** The list of IDs of users mentioned in the tweet. */
21
+ mentionedUsers: string[] = [];
22
+
23
+ /** The list of urls to various media mentioned in the tweet. */
24
+ media: string[] = [];
25
+
26
+ constructor(entities: IRawTweetEntities) {
27
+ // Extracting user mentions
28
+ if (entities.user_mentions) {
29
+ for (const user of entities.user_mentions) {
30
+ this.mentionedUsers.push(user.screen_name);
31
+ }
32
+ }
33
+
34
+ // Extracting urls
35
+ if (entities.urls) {
36
+ for (const url of entities.urls) {
37
+ this.urls.push(url.expanded_url);
38
+ }
39
+ }
40
+
41
+ // Extracting hashtags
42
+ if (entities.hashtags) {
43
+ for (const hashtag of entities.hashtags) {
44
+ this.hashtags.push(hashtag.text);
45
+ }
46
+ }
47
+
48
+ // Extracting media urls (if any)
49
+ if (entities.media) {
50
+ for (const media of entities.media) {
51
+ this.media.push(media.media_url_https);
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ /**
58
+ * The details of a single Tweet.
59
+ *
60
+ * @public
61
+ */
62
+ export class Tweet implements ITweet {
63
+ /** The rest id of the tweet. */
64
+ id: string;
65
+
66
+ /** The rest id of the user who made the tweet. */
67
+ tweetBy: string;
68
+
69
+ /** The date and time of creation of the tweet, in UTC string format. */
70
+ createdAt: string;
71
+
72
+ /** Additional tweet entities like urls, mentions, etc. */
73
+ entities: TweetEntities;
74
+
75
+ /** The rest id of the tweet which is quoted in the tweet. */
76
+ quoted: string;
77
+
78
+ /** The full text content of the tweet. */
79
+ fullText: string;
80
+
81
+ /** The rest id of the user to which the tweet is a reply. */
82
+ replyTo: string;
83
+
84
+ /** The language in which the tweet is written. */
85
+ lang: string;
86
+
87
+ /** The number of quotes of the tweet. */
88
+ quoteCount: number;
89
+
90
+ /** The number of replies to the tweet. */
91
+ replyCount: number;
92
+
93
+ /** The number of retweets of the tweet. */
94
+ retweetCount: number;
95
+
96
+ /** The number of likes of the tweet. */
97
+ likeCount: number;
98
+
99
+ /**
100
+ * @param tweet - The raw tweet data.
101
+ */
102
+ constructor(tweet: IRawTweet) {
103
+ this.id = tweet.rest_id;
104
+ this.createdAt = tweet.legacy.created_at;
105
+ this.tweetBy = tweet.legacy.user_id_str;
106
+ this.entities = new TweetEntities(tweet.legacy.entities);
107
+ this.quoted = tweet.legacy.quoted_status_id_str;
108
+ this.fullText = normalizeText(tweet.legacy.full_text);
109
+ this.replyTo = tweet.legacy.in_reply_to_status_id_str;
110
+ this.lang = tweet.legacy.lang;
111
+ this.quoteCount = tweet.legacy.quote_count;
112
+ this.replyCount = tweet.legacy.reply_count;
113
+ this.retweetCount = tweet.legacy.retweet_count;
114
+ this.likeCount = tweet.legacy.favorite_count;
115
+ }
116
+ }
@@ -0,0 +1,72 @@
1
+ // TYPES
2
+ import { IUser } from '../types/User';
3
+ import { IUser as IRawUser } from 'rettiwt-core';
4
+
5
+ /**
6
+ * The details of a single user.
7
+ *
8
+ * @public
9
+ */
10
+ export class User implements IUser {
11
+ /** The rest id of the user. */
12
+ id: string;
13
+
14
+ /** The username/screenname of the user. */
15
+ userName: string;
16
+
17
+ /** The full name of the user. */
18
+ fullName: string;
19
+
20
+ /** The creation date of user's account. */
21
+ createdAt: string;
22
+
23
+ /** The user's description. */
24
+ description: string;
25
+
26
+ /** Whether the account is verified or not. */
27
+ isVerified: boolean;
28
+
29
+ /** The number of tweets liked by the user. */
30
+ favouritesCount: number;
31
+
32
+ /** The number of followers of the user. */
33
+ followersCount: number;
34
+
35
+ /** The number of following of the user. */
36
+ followingsCount: number;
37
+
38
+ /** The number of tweets made by the user. */
39
+ statusesCount: number;
40
+
41
+ /** The location of user as provided by user. */
42
+ location: string;
43
+
44
+ /** The rest id of the tweet pinned in the user's profile. */
45
+ pinnedTweet: string;
46
+
47
+ /** The url of the profile banner image. */
48
+ profileBanner: string;
49
+
50
+ /** The url of the profile image. */
51
+ profileImage: string;
52
+
53
+ /**
54
+ * @param user - The raw user data.
55
+ */
56
+ constructor(user: IRawUser) {
57
+ this.id = user.rest_id;
58
+ this.userName = user.legacy.screen_name;
59
+ this.fullName = user.legacy.name;
60
+ this.createdAt = user.legacy.created_at;
61
+ this.description = user.legacy.description;
62
+ this.isVerified = user.legacy.verified;
63
+ this.favouritesCount = user.legacy.favourites_count;
64
+ this.followersCount = user.legacy.followers_count;
65
+ this.followingsCount = user.legacy.friends_count;
66
+ this.statusesCount = user.legacy.statuses_count;
67
+ this.location = user.legacy.location;
68
+ this.pinnedTweet = user.legacy.pinned_tweet_ids_str[0];
69
+ this.profileBanner = user.legacy.profile_banner_url;
70
+ this.profileImage = user.legacy.profile_image_url_https;
71
+ }
72
+ }
@@ -0,0 +1,186 @@
1
+ // PACKAGES
2
+ import {
3
+ Request,
4
+ Args,
5
+ EResourceType,
6
+ ICursor as IRawCursor,
7
+ ITweet as IRawTweet,
8
+ IUser as IRawUser,
9
+ ITimelineTweet,
10
+ ITimelineUser,
11
+ IResponse,
12
+ EErrorCodes,
13
+ } from 'rettiwt-core';
14
+ import axios, { AxiosRequestConfig, AxiosRequestHeaders, AxiosResponse } from 'axios';
15
+ import { AuthCredential } from 'rettiwt-auth';
16
+
17
+ // ENUMS
18
+ import { EHttpStatus } from '../enums/HTTP';
19
+ import { EApiErrors } from '../enums/ApiErrors';
20
+
21
+ // MODELS
22
+ import { CursoredData } from '../models/CursoredData';
23
+ import { Tweet } from '../models/Tweet';
24
+ import { User } from '../models/User';
25
+
26
+ // HELPERS
27
+ import { findByFilter, findKeyByValue } from '../helper/JsonUtils';
28
+
29
+ /**
30
+ * The base service that handles all HTTP requests.
31
+ *
32
+ * @internal
33
+ */
34
+ export class FetcherService {
35
+ /** The credential to use for authenticating against Twitter API. */
36
+ private cred: AuthCredential;
37
+
38
+ /**
39
+ * @param cred - The credentials to use for authenticating against Twitter API.
40
+ */
41
+ constructor(cred: AuthCredential) {
42
+ this.cred = cred;
43
+ }
44
+
45
+ /**
46
+ * The middleware for handling any http error.
47
+ *
48
+ * @param res - The response object received.
49
+ * @returns The received response, if no HTTP errors are found.
50
+ */
51
+ private handleHttpError(res: AxiosResponse<IResponse<unknown>>): AxiosResponse<IResponse<unknown>> {
52
+ /**
53
+ * If the status code is not 200 =\> the HTTP request was not successful. hence throwing error
54
+ */
55
+ if (res.status != 200 && res.status in EHttpStatus) {
56
+ throw new Error(EHttpStatus[res.status]);
57
+ }
58
+
59
+ return res;
60
+ }
61
+
62
+ /**
63
+ * The middleware for handling any Twitter API-level errors.
64
+ *
65
+ * @param res - The response object received.
66
+ * @returns The received response, if no API errors are found.
67
+ */
68
+ private handleApiError(res: AxiosResponse<IResponse<unknown>>): AxiosResponse<IResponse<unknown>> {
69
+ // If error exists
70
+ if (res.data.errors && res.data.errors.length) {
71
+ // Getting the error code
72
+ const code: number = res.data.errors[0].code;
73
+
74
+ // Getting the error message
75
+ const message: string = EApiErrors[
76
+ findKeyByValue(EErrorCodes, `${code}`) as keyof typeof EApiErrors
77
+ ] as string;
78
+
79
+ // Throw the error
80
+ throw new Error(message);
81
+ }
82
+
83
+ return res;
84
+ }
85
+
86
+ /**
87
+ * Makes an HTTP request according to the given parameters.
88
+ *
89
+ * @param config - The request configuration.
90
+ * @returns The response received.
91
+ */
92
+ private async request(config: Request): Promise<AxiosResponse<IResponse<unknown>>> {
93
+ /**
94
+ * Creating axios request configuration from the input configuration.
95
+ */
96
+ const axiosRequest: AxiosRequestConfig = {
97
+ url: config.url,
98
+ method: config.type,
99
+ data: config.payload,
100
+ headers: JSON.parse(JSON.stringify(this.cred.toHeader())) as AxiosRequestHeaders,
101
+ };
102
+
103
+ /**
104
+ * After making the request, the response is then passed to HTTP error handling middlware for HTTP error handling.
105
+ */
106
+ return await axios<IResponse<unknown>>(axiosRequest)
107
+ .then((res) => this.handleHttpError(res))
108
+ .then((res) => this.handleApiError(res));
109
+ }
110
+
111
+ /**
112
+ * Extracts the required data based on the type of resource passed as argument.
113
+ *
114
+ * @param data - The data from which extraction is to be done.
115
+ * @param type - The type of data to extract.
116
+ * @typeParam BaseType - The base type of the raw data present in the input.
117
+ * @typeParam DeserializedType - The type of data produced after deserialization of BaseType.
118
+ * @returns The extracted data.
119
+ */
120
+ private extractData<DeserializedType extends Tweet | User>(
121
+ data: NonNullable<unknown>,
122
+ type: EResourceType,
123
+ ): CursoredData<DeserializedType> {
124
+ /**
125
+ * The required extracted data.
126
+ */
127
+ let required = [];
128
+
129
+ if (type == EResourceType.TWEET_DETAILS) {
130
+ required = findByFilter<IRawTweet>(data, '__typename', 'Tweet');
131
+ } else if (type == EResourceType.USER_DETAILS || type == EResourceType.USER_DETAILS_BY_ID) {
132
+ required = findByFilter<IRawUser>(data, '__typename', 'User');
133
+ } else if (type == EResourceType.TWEET_SEARCH || type == EResourceType.USER_LIKES) {
134
+ required = findByFilter<ITimelineTweet>(data, '__typename', 'TimelineTweet').map(
135
+ (item) => item.tweet_results.result,
136
+ );
137
+ } else {
138
+ required = findByFilter<ITimelineUser>(data, '__typename', 'TimelineUser').map(
139
+ (item) => item.user_results.result,
140
+ );
141
+ }
142
+
143
+ return new CursoredData(required, findByFilter<IRawCursor>(data, 'cursorType', 'Bottom')[0]?.value);
144
+ }
145
+
146
+ /**
147
+ * Fetches the requested resource from Twitter and returns it after processing.
148
+ *
149
+ * @param resourceType - The type of resource to fetch.
150
+ * @param args - Resource specific arguments.
151
+ * @typeParam OutType - The type of deserialized data returned.
152
+ * @returns The processed data requested from Twitter.
153
+ */
154
+ protected async fetch<OutType extends Tweet | User>(
155
+ resourceType: EResourceType,
156
+ args: Args,
157
+ ): Promise<CursoredData<OutType>> {
158
+ // Preparing the HTTP request
159
+ const request: Request = new Request(resourceType, args);
160
+
161
+ // Getting the raw data
162
+ const res = await this.request(request).then((res) => res.data);
163
+
164
+ // Extracting data
165
+ const data = this.extractData<OutType>(res, resourceType);
166
+
167
+ return data;
168
+ }
169
+
170
+ /**
171
+ * Posts the requested resource to Twitter and returns the response.
172
+ *
173
+ * @param resourceType - The type of resource to post.
174
+ * @param args - Resource specific arguments.
175
+ * @returns Whether posting was successful or not.
176
+ */
177
+ protected async post(resourceType: EResourceType, args: Args): Promise<boolean> {
178
+ // Preparing the HTTP request
179
+ const request: Request = new Request(resourceType, args);
180
+
181
+ // Posting the data
182
+ await this.request(request);
183
+
184
+ return true;
185
+ }
186
+ }
@@ -0,0 +1,153 @@
1
+ // PACKAGES
2
+ import { EResourceType, TweetFilter } from 'rettiwt-core';
3
+ import { AuthCredential } from 'rettiwt-auth';
4
+
5
+ // SERVICES
6
+ import { FetcherService } from './FetcherService';
7
+
8
+ // MODELS
9
+ import { Tweet } from '../models/Tweet';
10
+ import { User } from '../models/User';
11
+ import { CursoredData } from '../models/CursoredData';
12
+
13
+ /**
14
+ * Handles fetching of data related to tweets.
15
+ *
16
+ * @public
17
+ */
18
+ export class TweetService extends FetcherService {
19
+ /**
20
+ * @param cred - The credentials to use for authenticating against Twitter API.
21
+ *
22
+ * @internal
23
+ */
24
+ constructor(cred: AuthCredential) {
25
+ super(cred);
26
+ }
27
+
28
+ /**
29
+ * Search for tweets using a query.
30
+ *
31
+ * @param query - The query be used for searching the tweets.
32
+ * @param count - The number of tweets to fetch, must be \<= 20.
33
+ * @param cursor - The cursor to the batch of tweets to fetch.
34
+ * @returns The list of tweets that match the given filter.
35
+ *
36
+ * @public
37
+ */
38
+ async search(query: TweetFilter, count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
39
+ // Fetching the requested data
40
+ const data = await this.fetch<Tweet>(EResourceType.TWEET_SEARCH, {
41
+ filter: query,
42
+ count: count,
43
+ cursor: cursor,
44
+ });
45
+
46
+ // Sorting the tweets by date, from recent to oldest
47
+ data.list.sort((a, b) => new Date(b.createdAt).valueOf() - new Date(a.createdAt).valueOf());
48
+
49
+ return data;
50
+ }
51
+
52
+ /**
53
+ * Get the details of a tweet.
54
+ *
55
+ * @param id - The id of the target tweet.
56
+ * @returns The details of a single tweet with the given tweet id.
57
+ *
58
+ * @public
59
+ */
60
+ async details(id: string): Promise<Tweet> {
61
+ // Fetching the requested data
62
+ const data = await this.fetch<Tweet>(EResourceType.TWEET_DETAILS, { id: id });
63
+
64
+ return data.list[0];
65
+ }
66
+
67
+ /**
68
+ * Get the list of users who liked a tweet.
69
+ *
70
+ * @param tweetId - The rest id of the target tweet.
71
+ * @param count - The number of favoriters to fetch, must be \<= 100.
72
+ * @param cursor - The cursor to the batch of favoriters to fetch.
73
+ * @returns The list of users who liked the given tweet.
74
+ *
75
+ * @public
76
+ */
77
+ async favoriters(tweetId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
78
+ // Fetching the requested data
79
+ const data = await this.fetch<User>(EResourceType.TWEET_FAVORITERS, {
80
+ id: tweetId,
81
+ count: count,
82
+ cursor: cursor,
83
+ });
84
+
85
+ return data;
86
+ }
87
+
88
+ /**
89
+ * Get the list of users who retweeted a tweet.
90
+ *
91
+ * @param tweetId - The rest id of the target tweet.
92
+ * @param count - The number of retweeters to fetch, must be \<= 100.
93
+ * @param cursor - The cursor to the batch of retweeters to fetch.
94
+ * @returns The list of users who retweeted the given tweet.
95
+ *
96
+ * @public
97
+ */
98
+ async retweeters(tweetId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
99
+ // Fetching the requested data
100
+ const data = await this.fetch<User>(EResourceType.TWEET_RETWEETERS, {
101
+ id: tweetId,
102
+ count: count,
103
+ cursor: cursor,
104
+ });
105
+
106
+ return data;
107
+ }
108
+
109
+ /**
110
+ * Post a tweet.
111
+ *
112
+ * @param tweetText - The text to be posted, length must be \<= 280 characters.
113
+ * @returns Whether posting was successful or not.
114
+ *
115
+ * @public
116
+ */
117
+ async tweet(tweetText: string): Promise<boolean> {
118
+ // Posting the tweet
119
+ const data = await this.post(EResourceType.CREATE_TWEET, { tweetText: tweetText });
120
+
121
+ return data;
122
+ }
123
+
124
+ /**
125
+ * Favorite the tweet with the given id.
126
+ *
127
+ * @param tweetId - The id of the tweet to be favorited.
128
+ * @returns Whether favoriting was successful or not.
129
+ *
130
+ * @public
131
+ */
132
+ async favorite(tweetId: string): Promise<boolean> {
133
+ // Favoriting the tweet
134
+ const data = await this.post(EResourceType.FAVORITE_TWEET, { id: tweetId });
135
+
136
+ return data;
137
+ }
138
+
139
+ /**
140
+ * Retweet the tweet with the given id.
141
+ *
142
+ * @param tweetId - The id of the tweet with the given id.
143
+ * @returns Whether retweeting was successful or not.
144
+ *
145
+ * @public
146
+ */
147
+ async retweet(tweetId: string): Promise<boolean> {
148
+ // Retweeting the tweet
149
+ const data = await this.post(EResourceType.CREATE_RETWEET, { id: tweetId });
150
+
151
+ return data;
152
+ }
153
+ }
@@ -0,0 +1,117 @@
1
+ // PACKAGES
2
+ import { EResourceType } from 'rettiwt-core';
3
+ import { AuthCredential } from 'rettiwt-auth';
4
+
5
+ // SERVICES
6
+ import { FetcherService } from './FetcherService';
7
+
8
+ // MODELS
9
+ import { User } from '../models/User';
10
+ import { Tweet } from '../models/Tweet';
11
+
12
+ // TYPES
13
+ import { CursoredData } from '../models/CursoredData';
14
+
15
+ /**
16
+ * Handles fetching of data related to user account
17
+ *
18
+ * @public
19
+ */
20
+ export class UserService extends FetcherService {
21
+ /**
22
+ * @param cred - The credentials to use for authenticating against Twitter API.
23
+ *
24
+ * @internal
25
+ */
26
+ constructor(cred: AuthCredential) {
27
+ super(cred);
28
+ }
29
+
30
+ /**
31
+ * Get the details of a user.
32
+ *
33
+ * @param id - The username/id of the target user.
34
+ * @returns The details of the given user.
35
+ *
36
+ * @public
37
+ */
38
+ async details(id: string): Promise<User> {
39
+ let data: CursoredData<User>;
40
+
41
+ // If username is given
42
+ if (isNaN(parseFloat(id))) {
43
+ // Fetching the requested data
44
+ data = await this.fetch<User>(EResourceType.USER_DETAILS, { id: id });
45
+ }
46
+ // If id is given
47
+ else {
48
+ // Fetching the requested data
49
+ data = await this.fetch<User>(EResourceType.USER_DETAILS_BY_ID, { id: id });
50
+ }
51
+
52
+ return data.list[0];
53
+ }
54
+
55
+ /**
56
+ * Get the list of users who are followed by the given user.
57
+ *
58
+ * @param userId - The rest id of the target user.
59
+ * @param count - The number of following to fetch, must be \<= 100.
60
+ * @param cursor - The cursor to the batch of following to fetch.
61
+ * @returns The list of users followed by the target user.
62
+ *
63
+ * @public
64
+ */
65
+ async following(userId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
66
+ // Fetching the requested data
67
+ const data = await this.fetch<User>(EResourceType.USER_FOLLOWING, {
68
+ id: userId,
69
+ count: count,
70
+ cursor: cursor,
71
+ });
72
+
73
+ return data;
74
+ }
75
+
76
+ /**
77
+ * Get the list followers of a given user.
78
+ *
79
+ * @param userId - The rest id of the target user.
80
+ * @param count - The number of followers to fetch, must be \<= 100.
81
+ * @param cursor - The cursor to the batch of followers to fetch.
82
+ * @returns The list of users following the target user.
83
+ *
84
+ * @public
85
+ */
86
+ async followers(userId: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
87
+ // Fetching the requested data
88
+ const data = await this.fetch<User>(EResourceType.USER_FOLLOWERS, {
89
+ id: userId,
90
+ count: count,
91
+ cursor: cursor,
92
+ });
93
+
94
+ return data;
95
+ }
96
+
97
+ /**
98
+ * Get the list of tweets liked by the given user.
99
+ *
100
+ * @param userId - The rest id of the target user.
101
+ * @param count - The number of likes to fetch, must be \<= 100.
102
+ * @param cursor - The cursor to the batch of likes to fetch.
103
+ * @returns The list of tweets liked by the target user.
104
+ *
105
+ * @public
106
+ */
107
+ async likes(userId: string, count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
108
+ // Fetching the requested data
109
+ const data = await this.fetch<Tweet>(EResourceType.USER_LIKES, {
110
+ id: userId,
111
+ count: count,
112
+ cursor: cursor,
113
+ });
114
+
115
+ return data;
116
+ }
117
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The cursor to the batch of data to be fetched.
3
+ *
4
+ * @public
5
+ */
6
+ export interface ICursor {
7
+ /** The cursor string. */
8
+ value: string;
9
+ }
10
+
11
+ /**
12
+ * The data that us fetched batch-wise along with a cursor.
13
+ *
14
+ * @typeParam T - Type of data present in the list.
15
+ *
16
+ * @public
17
+ */
18
+ export interface ICursoredData<T> {
19
+ /** The list of data of the given type. */
20
+ list: T[];
21
+
22
+ /** The cursor to the next batch of data. */
23
+ next: ICursor;
24
+ }