rettiwt-api 1.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 (156) hide show
  1. package/.dockerignore +2 -0
  2. package/.gitattributes +3 -0
  3. package/Dockerfile +9 -0
  4. package/README.md +38 -0
  5. package/dist/config/env.d.ts +5 -0
  6. package/dist/config/env.js +9 -0
  7. package/dist/config/env.js.map +1 -0
  8. package/dist/index.d.ts +10 -0
  9. package/dist/index.js +23 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/models/graphql/Global.d.ts +4 -0
  12. package/dist/models/graphql/Global.js +13 -0
  13. package/dist/models/graphql/Global.js.map +1 -0
  14. package/dist/models/graphql/TweetTypes.d.ts +6 -0
  15. package/dist/models/graphql/TweetTypes.js +156 -0
  16. package/dist/models/graphql/TweetTypes.js.map +1 -0
  17. package/dist/models/graphql/UserTypes.d.ts +3 -0
  18. package/dist/models/graphql/UserTypes.js +139 -0
  19. package/dist/models/graphql/UserTypes.js.map +1 -0
  20. package/dist/queries/RootQuery.d.ts +4 -0
  21. package/dist/queries/RootQuery.js +59 -0
  22. package/dist/queries/RootQuery.js.map +1 -0
  23. package/dist/resolvers/ResolverBase.d.ts +5 -0
  24. package/dist/resolvers/ResolverBase.js +11 -0
  25. package/dist/resolvers/ResolverBase.js.map +1 -0
  26. package/dist/resolvers/TweetResolver.d.ts +54 -0
  27. package/dist/resolvers/TweetResolver.js +328 -0
  28. package/dist/resolvers/TweetResolver.js.map +1 -0
  29. package/dist/resolvers/UserResolver.d.ts +47 -0
  30. package/dist/resolvers/UserResolver.js +302 -0
  31. package/dist/resolvers/UserResolver.js.map +1 -0
  32. package/dist/server.d.ts +1 -0
  33. package/dist/server.js +75 -0
  34. package/dist/server.js.map +1 -0
  35. package/dist/services/AuthService.d.ts +17 -0
  36. package/dist/services/AuthService.js +103 -0
  37. package/dist/services/AuthService.js.map +1 -0
  38. package/dist/services/CacheService.d.ts +25 -0
  39. package/dist/services/CacheService.js +141 -0
  40. package/dist/services/CacheService.js.map +1 -0
  41. package/dist/services/FetcherService.d.ts +30 -0
  42. package/dist/services/FetcherService.js +171 -0
  43. package/dist/services/FetcherService.js.map +1 -0
  44. package/dist/services/data/TweetService.d.ts +43 -0
  45. package/dist/services/data/TweetService.js +229 -0
  46. package/dist/services/data/TweetService.js.map +1 -0
  47. package/dist/services/data/UserAccountService.d.ts +49 -0
  48. package/dist/services/data/UserAccountService.js +250 -0
  49. package/dist/services/data/UserAccountService.js.map +1 -0
  50. package/dist/services/helper/Deserializers.d.ts +19 -0
  51. package/dist/services/helper/Deserializers.js +115 -0
  52. package/dist/services/helper/Deserializers.js.map +1 -0
  53. package/dist/services/helper/Extractors.d.ts +101 -0
  54. package/dist/services/helper/Extractors.js +409 -0
  55. package/dist/services/helper/Extractors.js.map +1 -0
  56. package/dist/services/helper/Headers.d.ts +9 -0
  57. package/dist/services/helper/Headers.js +47 -0
  58. package/dist/services/helper/Headers.js.map +1 -0
  59. package/dist/services/helper/Parser.d.ts +28 -0
  60. package/dist/services/helper/Parser.js +104 -0
  61. package/dist/services/helper/Parser.js.map +1 -0
  62. package/dist/services/helper/Urls.d.ts +74 -0
  63. package/dist/services/helper/Urls.js +114 -0
  64. package/dist/services/helper/Urls.js.map +1 -0
  65. package/dist/test/Test.js +2 -0
  66. package/dist/test/Test.js.map +1 -0
  67. package/dist/types/Authentication.d.ts +15 -0
  68. package/dist/types/Authentication.js +5 -0
  69. package/dist/types/Authentication.js.map +1 -0
  70. package/dist/types/HTTP.d.ts +22 -0
  71. package/dist/types/HTTP.js +30 -0
  72. package/dist/types/HTTP.js.map +1 -0
  73. package/dist/types/Service.d.ts +27 -0
  74. package/dist/types/Service.js +19 -0
  75. package/dist/types/Service.js.map +1 -0
  76. package/dist/types/Tweet.d.ts +40 -0
  77. package/dist/types/Tweet.js +5 -0
  78. package/dist/types/Tweet.js.map +1 -0
  79. package/dist/types/UserAccount.d.ts +19 -0
  80. package/dist/types/UserAccount.js +4 -0
  81. package/dist/types/UserAccount.js.map +1 -0
  82. package/dist/types/graphql/Errors.d.ts +15 -0
  83. package/dist/types/graphql/Errors.js +23 -0
  84. package/dist/types/graphql/Errors.js.map +1 -0
  85. package/dist/types/raw/auth/Cookie.d.ts +16 -0
  86. package/dist/types/raw/auth/Cookie.js +3 -0
  87. package/dist/types/raw/auth/Cookie.js.map +1 -0
  88. package/dist/types/raw/tweet/Favouriters.d.ts +164 -0
  89. package/dist/types/raw/tweet/Favouriters.js +3 -0
  90. package/dist/types/raw/tweet/Favouriters.js.map +1 -0
  91. package/dist/types/raw/tweet/Retweeters.d.ts +171 -0
  92. package/dist/types/raw/tweet/Retweeters.js +3 -0
  93. package/dist/types/raw/tweet/Retweeters.js.map +1 -0
  94. package/dist/types/raw/tweet/Tweet.d.ts +746 -0
  95. package/dist/types/raw/tweet/Tweet.js +3 -0
  96. package/dist/types/raw/tweet/Tweet.js.map +1 -0
  97. package/dist/types/raw/tweet/Tweets.d.ts +386 -0
  98. package/dist/types/raw/tweet/Tweets.js +3 -0
  99. package/dist/types/raw/tweet/Tweets.js.map +1 -0
  100. package/dist/types/raw/user/Followers.d.ts +176 -0
  101. package/dist/types/raw/user/Followers.js +3 -0
  102. package/dist/types/raw/user/Followers.js.map +1 -0
  103. package/dist/types/raw/user/Following.d.ts +176 -0
  104. package/dist/types/raw/user/Following.js +3 -0
  105. package/dist/types/raw/user/Following.js.map +1 -0
  106. package/dist/types/raw/user/Likes.d.ts +1059 -0
  107. package/dist/types/raw/user/Likes.js +3 -0
  108. package/dist/types/raw/user/Likes.js.map +1 -0
  109. package/dist/types/raw/user/Tweets.d.ts +2428 -0
  110. package/dist/types/raw/user/Tweets.js +3 -0
  111. package/dist/types/raw/user/Tweets.js.map +1 -0
  112. package/dist/types/raw/user/User.d.ts +117 -0
  113. package/dist/types/raw/user/User.js +3 -0
  114. package/dist/types/raw/user/User.js.map +1 -0
  115. package/dist/types/raw/user/Users.d.ts +120 -0
  116. package/dist/types/raw/user/Users.js +3 -0
  117. package/dist/types/raw/user/Users.js.map +1 -0
  118. package/environment.d.ts +11 -0
  119. package/package.json +40 -0
  120. package/src/config/env.ts +5 -0
  121. package/src/index.ts +19 -0
  122. package/src/models/graphql/Global.ts +10 -0
  123. package/src/models/graphql/TweetTypes.ts +154 -0
  124. package/src/models/graphql/UserTypes.ts +137 -0
  125. package/src/queries/RootQuery.ts +56 -0
  126. package/src/resolvers/ResolverBase.ts +12 -0
  127. package/src/resolvers/TweetResolver.ts +257 -0
  128. package/src/resolvers/UserResolver.ts +239 -0
  129. package/src/server.ts +36 -0
  130. package/src/services/AuthService.ts +58 -0
  131. package/src/services/CacheService.ts +70 -0
  132. package/src/services/FetcherService.ts +84 -0
  133. package/src/services/data/TweetService.ts +163 -0
  134. package/src/services/data/UserAccountService.ts +187 -0
  135. package/src/services/helper/Deserializers.ts +95 -0
  136. package/src/services/helper/Extractors.ts +455 -0
  137. package/src/services/helper/Headers.ts +45 -0
  138. package/src/services/helper/Parser.ts +108 -0
  139. package/src/services/helper/Urls.ts +109 -0
  140. package/src/types/Authentication.ts +16 -0
  141. package/src/types/HTTP.ts +23 -0
  142. package/src/types/Service.ts +36 -0
  143. package/src/types/Tweet.ts +44 -0
  144. package/src/types/UserAccount.ts +21 -0
  145. package/src/types/graphql/Errors.ts +16 -0
  146. package/src/types/raw/auth/Cookie.ts +16 -0
  147. package/src/types/raw/tweet/Favouriters.ts +193 -0
  148. package/src/types/raw/tweet/Retweeters.ts +201 -0
  149. package/src/types/raw/tweet/Tweet.ts +882 -0
  150. package/src/types/raw/tweet/Tweets.ts +444 -0
  151. package/src/types/raw/user/Followers.ts +208 -0
  152. package/src/types/raw/user/Following.ts +208 -0
  153. package/src/types/raw/user/Likes.ts +1247 -0
  154. package/src/types/raw/user/Tweets.ts +2847 -0
  155. package/src/types/raw/user/User.ts +135 -0
  156. package/tsconfig.json +95 -0
@@ -0,0 +1,70 @@
1
+ // PACKAGES
2
+ import NodeCache from 'node-cache';
3
+
4
+ // PARSERS
5
+ import * as Parsers from './helper/Parser';
6
+
7
+ /**
8
+ * @summary Handles reading and writing of data from and to cache.
9
+ *
10
+ * **Note**: To be able to CacheService, the data to be cached must have a unique "id" field.
11
+ */
12
+ export class CacheService {
13
+ // MEMBER DATA
14
+ private static instance: CacheService; // To store the current instance of this service
15
+ private client: NodeCache; // To store the redis client instance
16
+
17
+ // MEMBER METHODS
18
+ private constructor() {
19
+ // Initializing new cache
20
+ this.client = new NodeCache();
21
+ }
22
+
23
+ /**
24
+ * @returns The current working instance of CacheService
25
+ */
26
+ static async getInstance(): Promise<CacheService> {
27
+ // If an instance doesnt exists already
28
+ if (!this.instance) {
29
+ this.instance = new CacheService();
30
+ return this.instance;
31
+ }
32
+ // If an instance already exists, returning it
33
+ else {
34
+ return this.instance;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * @summary Stores the input data into the cache.
40
+ * @returns Whether writing to cache was successful or not
41
+ * @param data The input data to store
42
+ */
43
+ async write(data: any): Promise<void> {
44
+ // Converting the data to a list of data
45
+ data = Parsers.dataToList(data);
46
+
47
+ // Iterating over the list of data
48
+ for (let item of data) {
49
+ // Storing whether data is already cached or not
50
+ let cached = this.client.has(Parsers.findJSONKey(item, 'id'));
51
+
52
+ // If data does not already exist in cache
53
+ if(!cached) {
54
+ // Adding data to cache
55
+ this.client.set(Parsers.findJSONKey(item, 'id'), item);
56
+ }
57
+ }
58
+ }
59
+
60
+ /**
61
+ * @returns The data with the given id/rest id from cache
62
+ * @param id The id/rest id of the data to be fetched from cache
63
+ */
64
+ async read(id: string): Promise<any> {
65
+ // Getting data from cache
66
+ let res = this.client.get(id);
67
+
68
+ return res;
69
+ }
70
+ }
@@ -0,0 +1,84 @@
1
+ // PACKAGES
2
+ import { curly, CurlyResult } from 'node-libcurl';
3
+
4
+ // SERVICES
5
+ import { AuthService } from './AuthService';
6
+ import { CacheService } from './CacheService';
7
+
8
+ // TYPES
9
+ import { HttpStatus } from "../types/HTTP";
10
+ import { Result as RawUser } from '../types/raw/user/User';
11
+ import { Result as RawTweet } from '../types/raw/tweet/Tweet';
12
+
13
+ // HELPERS
14
+ import * as Headers from './helper/Headers'
15
+ import * as Deserializers from './helper/Deserializers';
16
+
17
+ /**
18
+ * @service The base serivice from which all other data services derive their behaviour
19
+ */
20
+ export class FetcherService {
21
+ // MEMBER DATA
22
+ private auth: AuthService; // To store the auth service instance to use for authentication
23
+
24
+ // MEMBER METHODS
25
+ constructor(auth: AuthService) {
26
+ this.auth = auth;
27
+ }
28
+
29
+ /**
30
+ * @summary Throws the appropriate http error after evaluation of the status code of reponse
31
+ * @param res The response object received from http communication
32
+ */
33
+ private handleHTTPError(res: CurlyResult): CurlyResult {
34
+ if (res.statusCode != 200 && res.statusCode in HttpStatus) {
35
+ throw new Error(HttpStatus[res.statusCode])
36
+ }
37
+
38
+ return res;
39
+ }
40
+
41
+ /**
42
+ * @returns The absolute raw json data from give url
43
+ * @param url The url to fetch data from
44
+ * @param authenticated Whether to authenticate requests or not
45
+ */
46
+ protected async request<DataType>(url: string, authenticated: boolean = false): Promise<CurlyResult<DataType>> {
47
+ // Fetching the data
48
+ let res = await curly.get(url, {
49
+ httpHeader: authenticated ? Headers.authorizedHeader(await this.auth.getAuthCredentials()) : Headers.guestHeader(await this.auth.getGuestCredentials()),
50
+ sslVerifyPeer: false
51
+ }).then(res => this.handleHTTPError(res));
52
+
53
+ return res;
54
+ }
55
+
56
+ /**
57
+ * @summary Caches the extracted data
58
+ * @param data The extracted data to be cached
59
+ */
60
+ protected async cacheData(data: any): Promise<void> {
61
+ // Creating an instance of cache
62
+ let cache = await CacheService.getInstance();
63
+
64
+ // Parsing the extracted data
65
+ let users = data.users.map((user: RawUser) => Deserializers.toUser(user));
66
+ let tweets = data.tweets.map((tweet: RawTweet) => Deserializers.toTweet(tweet));
67
+
68
+ // Caching the data
69
+ cache.write(users);
70
+ cache.write(tweets);
71
+ }
72
+
73
+ /**
74
+ * @returns The data with the given id (if it exists in cache)
75
+ * @param id The id of the data to be read from cache
76
+ */
77
+ protected async readData(id: string): Promise<any> {
78
+ // Creating an instance of cache
79
+ let cache = await CacheService.getInstance();
80
+
81
+ // Reading data from cache
82
+ return cache.read(id);
83
+ }
84
+ }
@@ -0,0 +1,163 @@
1
+ // SERVICES
2
+ import { FetcherService } from "../FetcherService";
3
+ import { AuthService } from "../AuthService";
4
+
5
+ // TYPES
6
+ import { TweetFilter, Tweet } from "../../types/Tweet";
7
+ import { User } from "../../types/UserAccount";
8
+ import { CursoredData } from '../../types/Service';
9
+ import RawTweet from '../../types/raw/tweet/Tweet';
10
+ import RawTweets from '../../types/raw/tweet/Tweets';
11
+ import RawLikers from '../../types/raw/tweet/Favouriters';
12
+ import RawRetweeters from '../../types/raw/tweet/Retweeters';
13
+
14
+ // URLS
15
+ import * as Urls from '../helper/Urls';
16
+
17
+ // EXTRACTORS
18
+ import * as Extractors from "../helper/Extractors";
19
+
20
+ // DESERIALIZERS
21
+ import * as Deserializers from '../helper/Deserializers';
22
+
23
+ // PARSERS
24
+ import { toQueryString } from '../helper/Parser';
25
+
26
+ /**
27
+ * A service that deals with fetching of data related to tweets
28
+ */
29
+ export class TweetService extends FetcherService {
30
+ // MEMBER METHODS
31
+ constructor(auth: AuthService) {
32
+ super(auth);
33
+ }
34
+
35
+ /**
36
+ * @returns The list of tweets that match the given filter
37
+ * @param filter The filter be used for searching the tweets
38
+ * @param count The number of tweets to fetch
39
+ * @param cursor The cursor to the next batch of tweets. If blank, first batch is fetched
40
+ */
41
+ async getTweets(filter: TweetFilter, count: number, cursor: string): Promise<CursoredData<Tweet>> {
42
+ // Getting the raw data
43
+ let res = await this.request<RawTweets>(Urls.tweetsUrl(toQueryString(filter), count, cursor), false).then(res => res.data);
44
+
45
+ // Extracting data
46
+ let data = Extractors.extractTweets(res);
47
+
48
+ // Caching data
49
+ this.cacheData(data);
50
+
51
+ // Parsing data
52
+ let tweets = data.required.map(item => Deserializers.toTweet(item));
53
+
54
+ return {
55
+ list: tweets,
56
+ next: { value: data.cursor }
57
+ };
58
+ }
59
+
60
+ /**
61
+ * @returns The details of a single tweet with the given tweet id
62
+ * @param tweetId The rest id of the target tweet
63
+ */
64
+ async getTweetById(tweetId: string): Promise<Tweet> {
65
+ // Getting data from cache
66
+ let cachedData = await this.readData(tweetId);
67
+
68
+ // If data exists in cache
69
+ if (cachedData) {
70
+ return cachedData;
71
+ }
72
+ // If data does not exist in cache
73
+ else {
74
+ // Fetching the raw data
75
+ let res = await this.request<RawTweet>(Urls.tweetDetailsUrl(tweetId)).then(res => res.data);
76
+
77
+ // Extracting data
78
+ let data = Extractors.extractTweet(res, tweetId);
79
+
80
+ // Caching data
81
+ this.cacheData(data);
82
+
83
+ // Parsing data
84
+ let tweet = Deserializers.toTweet(data.required[0]);
85
+
86
+ return tweet;
87
+ }
88
+ }
89
+
90
+ /**
91
+ * @returns The list of users who liked the given tweet
92
+ * @param tweetId The rest id of the target tweet
93
+ * @param count The batch size of the list
94
+ * @param cursor The cursor to the next batch of users. If blank, first batch is fetched
95
+ */
96
+ async getTweetLikers(tweetId: string, count: number, cursor: string): Promise<CursoredData<User>> {
97
+ // Fetching the raw data
98
+ let res = await this.request<RawLikers>(Urls.tweetLikesUrl(tweetId, count, cursor)).then(res => res.data);
99
+
100
+ // Extracting data
101
+ let data = Extractors.extractTweetLikers(res);
102
+
103
+ // Caching data
104
+ this.cacheData(data);
105
+
106
+ // Parsing data
107
+ let users = data.required.map(item => Deserializers.toUser(item));
108
+
109
+ return {
110
+ list: users,
111
+ next: { value: data.cursor }
112
+ };
113
+ }
114
+
115
+ /**
116
+ * @returns The list of users who retweeted the given tweet
117
+ * @param tweetId The rest id of the target tweet
118
+ * @param count The batch size of the list
119
+ * @param cursor The cursor to the next batch of users. If blank, first batch is fetched
120
+ */
121
+ async getTweetRetweeters(tweetId: string, count: number, cursor: string): Promise<CursoredData<User>> {
122
+ // Fetching the raw data
123
+ let res = await this.request<RawRetweeters>(Urls.tweetRetweetUrl(tweetId, count, cursor)).then(res => res.data);
124
+
125
+ // Extracting data
126
+ let data = Extractors.extractTweetRetweeters(res);
127
+
128
+ // Caching data
129
+ this.cacheData(data);
130
+
131
+ // Parsing data
132
+ let users = data.required.map(item => Deserializers.toUser(item));
133
+
134
+ return {
135
+ list: users,
136
+ next: { value: data.cursor }
137
+ };
138
+ }
139
+
140
+ /**
141
+ * @returns The list of replies to the given tweet
142
+ * @param tweetId The rest id of the target tweet
143
+ * @param cursor The cursor to the next batch of replies. If blank, first batch is fetched
144
+ */
145
+ async getTweetReplies(tweetId: string, cursor: string): Promise<CursoredData<Tweet>> {
146
+ // Fetching the raw data
147
+ let res = await this.request<RawTweet>(Urls.tweetRepliesUrl(tweetId, cursor)).then(res => res.data);
148
+
149
+ // Extracting data
150
+ let data = Extractors.extractTweetReplies(res, tweetId);
151
+
152
+ // Caching data
153
+ this.cacheData(data);
154
+
155
+ // Parsing data
156
+ let tweets = data.required.map(item => Deserializers.toTweet(item));
157
+
158
+ return {
159
+ list: tweets,
160
+ next: { value: data.cursor }
161
+ };
162
+ }
163
+ }
@@ -0,0 +1,187 @@
1
+ // SERVICES
2
+ import { FetcherService } from '../FetcherService';
3
+ import { AuthService } from '../AuthService';
4
+
5
+ // TYPES
6
+ import { User } from '../../types/UserAccount';
7
+ import { Tweet } from '../../types/Tweet';
8
+ import { CursoredData } from '../../types/Service';
9
+ import RawUser from '../../types/raw/user/User';
10
+ import RawUserTweets from '../../types/raw/user/Tweets';
11
+ import RawUserFollowers from '../../types/raw/user/Followers';
12
+ import RawUserFollowing from '../../types/raw/user/Following';
13
+ import RawUserLikes from '../../types/raw/user/Likes';
14
+
15
+ // URLS
16
+ import * as Urls from '../helper/Urls';
17
+
18
+ // EXTRACTORS
19
+ import * as Extractors from '../helper/Extractors';
20
+
21
+ // DESERIALIZERS
22
+ import * as Deserializers from '../helper/Deserializers';
23
+
24
+ /**
25
+ * A service that deals with fetching of data related to user account
26
+ */
27
+ export class UserAccountService extends FetcherService {
28
+ // MEMBER METHODS
29
+ constructor(auth: AuthService) {
30
+ super(auth);
31
+ }
32
+
33
+ /**
34
+ * @returns The user account details of the given user
35
+ * @param screenName The screen name of the target user.
36
+ */
37
+ async getUserAccountDetails(screenName: string): Promise<User> {
38
+ // Fetching the raw data
39
+ let res: RawUser = await this.request<RawUser>(Urls.userAccountUrl(screenName), false).then(res => res.data);
40
+
41
+ // Extracting data
42
+ let data = Extractors.extractUserAccountDetails(res);
43
+
44
+ // Caching data
45
+ this.cacheData(data);
46
+
47
+ // Parsing data
48
+ let user = Deserializers.toUser(data.required[0]);
49
+
50
+ return user;
51
+ }
52
+
53
+ /**
54
+ * @returns The user account details of the user with given rest id
55
+ * @param restId The screen name of the target user.
56
+ */
57
+ async getUserAccountDetailsById(restId: string): Promise<User> {
58
+ // Getting data from cache
59
+ let cachedData = await this.readData(restId);
60
+
61
+ // If data exists in cache
62
+ if(cachedData) {
63
+ return cachedData;
64
+ }
65
+ // If data does not exist in cache
66
+ else {
67
+ // Fetchin the raw data
68
+ let res = await this.request<RawUser>(Urls.userAccountByIdUrl(restId), false).then(res => res.data);
69
+
70
+ // Extracting data
71
+ let data = Extractors.extractUserAccountDetails(res);
72
+
73
+ // Caching data
74
+ this.cacheData(data);
75
+
76
+ // Parsing data
77
+ let user = Deserializers.toUser(data.required[0]);
78
+
79
+ return user;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @returns The list of users followed by the target user
85
+ * @param userId The rest id of the target user
86
+ * @param count The batch size of the list
87
+ * @param cursor The cursor to next batch. If blank, first batch is fetched
88
+ */
89
+ async getUserFollowing(userId: string, count: number, cursor: string): Promise<CursoredData<User>> {
90
+ // Fetchin the raw data
91
+ let res = await this.request<RawUserFollowing>(Urls.userFollowingUrl(userId, count, cursor)).then(res => res.data);
92
+
93
+ // Extracting data
94
+ let data = Extractors.extractUserFollow(res);
95
+
96
+ // Caching data
97
+ this.cacheData(data);
98
+
99
+ // Parsing data
100
+ let users = data.required.map(item => Deserializers.toUser(item));
101
+
102
+ return {
103
+ list: users,
104
+ next: { value: data.cursor }
105
+ };
106
+ }
107
+
108
+ /**
109
+ * @returns The list of users following the target user
110
+ * @param userId The rest id of the target user
111
+ * @param count The batch size of the list
112
+ * @param cursor The cursor to next batch. If blank, first batch is fetched
113
+ */
114
+ async getUserFollowers(userId: string, count: number, cursor: string): Promise<CursoredData<User>> {
115
+ /**
116
+ * When fetching list of followers, the official Twitter API seems to be fetching n + 20 followers,
117
+ * where n is the actual required number of followers.
118
+ * So changing count to count - 20, fixes fetching more than required number of follower
119
+ */
120
+ // Fetching the raw data
121
+ let res = await this.request<RawUserFollowers>(Urls.userFollowersUrl(userId, (count > 20) ? (count - 20) : count, cursor)).then(res => res.data);
122
+
123
+ // Extracting data
124
+ let data = Extractors.extractUserFollow(res);
125
+
126
+ // Caching data
127
+ this.cacheData(data);
128
+
129
+ // Parsing data
130
+ let users = data.required.map(item => Deserializers.toUser(item));
131
+
132
+ return {
133
+ list: users,
134
+ next: { value: data.cursor }
135
+ };
136
+ }
137
+
138
+ /**
139
+ * @returns The list of tweets liked by the target user
140
+ * @param userId The rest id of the target user
141
+ * @param count The batch size of the list
142
+ * @param cursor The cursor to next batch. If blank, first batch is fetched
143
+ */
144
+ async getUserLikes(userId: string, count: number, cursor: string): Promise<CursoredData<Tweet>> {
145
+ // Fetching the raw data
146
+ let res = await this.request<RawUserLikes>(Urls.userLikesUrl(userId, count, cursor)).then(res => res.data);
147
+
148
+ // Extracting data
149
+ let data = Extractors.extractUserLikes(res);
150
+
151
+ // Caching data
152
+ this.cacheData(data);
153
+
154
+ // Parsing data
155
+ let tweets = data.required.map(item => Deserializers.toTweet(item));
156
+
157
+ return {
158
+ list: tweets,
159
+ next: { value: data.cursor }
160
+ };
161
+ }
162
+
163
+ /**
164
+ * @returns The list of tweets made by the target user
165
+ * @param userId The rest id of the target user
166
+ * @param count The batch size of the list
167
+ * @param cursor The cursor to next batch. If blank, first batch is fetched
168
+ */
169
+ async getUserTweets(userId: string, count: number, cursor: string): Promise<CursoredData<Tweet>> {
170
+ // Fetching the raw data
171
+ let res = await this.request<RawUserTweets>(Urls.userTweetsUrl(userId, count, cursor)).then(res => res.data);
172
+
173
+ // Extracting data
174
+ let data = Extractors.extractUserTweets(res);
175
+
176
+ // Caching data
177
+ this.cacheData(data);
178
+
179
+ // Parsing data
180
+ let tweets = data.required.map(item => Deserializers.toTweet(item));
181
+
182
+ return {
183
+ list: tweets,
184
+ next: { value: data.cursor }
185
+ };
186
+ }
187
+ };
@@ -0,0 +1,95 @@
1
+ // TYPES
2
+ import { User } from '../../types/UserAccount';
3
+ import { Tweet, TweetEntities } from '../../types/Tweet';
4
+ import { Result as RawUser } from '../../types/raw/user/User';
5
+ import { Result as RawTweet, Entities2 as RawTweetEntities } from '../../types/raw/tweet/Tweet';
6
+
7
+ // PARSERS
8
+ import * as Parsers from './Parser';
9
+
10
+ /**
11
+ * @returns A User object containing the user details
12
+ * @param data The raw user data from Twitter API
13
+ */
14
+ export function toUser(data: RawUser): User {
15
+ return {
16
+ id: data.rest_id,
17
+ userName: data.legacy.screen_name,
18
+ fullName: data.legacy.name,
19
+ createdAt: data.legacy.created_at,
20
+ description: data.legacy.description,
21
+ isVerified: data.legacy.verified,
22
+ favouritesCount: data.legacy.favourites_count,
23
+ followersCount: data.legacy.followers_count,
24
+ followingsCount: data.legacy.friends_count,
25
+ statusesCount: data.legacy.statuses_count,
26
+ location: data.legacy.location,
27
+ pinnedTweet: data.legacy.pinned_tweet_ids_str[0],
28
+ profileBanner: data.legacy.profile_banner_url,
29
+ profileImage: data.legacy.profile_image_url_https
30
+ };
31
+ }
32
+
33
+ /**
34
+ * @returns A TweetEntities object containing the various tweet entities
35
+ * @param data The raw tweet entities data from the response received from TwitterAPI
36
+ */
37
+ export function toTweetEntities(data: RawTweetEntities): TweetEntities {
38
+ let entities: TweetEntities = {
39
+ mentionedUsers: [],
40
+ urls: [],
41
+ media: [],
42
+ hashtags: []
43
+ };
44
+
45
+ // Extracting user mentions
46
+ if(data.user_mentions) {
47
+ for(let user of data.user_mentions) {
48
+ entities.mentionedUsers.push(user.id_str);
49
+ }
50
+ }
51
+
52
+ // Extracting urls
53
+ if(data.urls) {
54
+ for(let url of data.urls) {
55
+ entities.urls.push(url.expanded_url);
56
+ }
57
+ }
58
+
59
+ // Extracting hashtags
60
+ if(data.hashtags) {
61
+ for(let hashtag of data.hashtags) {
62
+ entities.hashtags.push(hashtag.text);
63
+ }
64
+ }
65
+
66
+ // Extracting media urls (if any)
67
+ if(data.media) {
68
+ for(const media of data.media) {
69
+ entities.media.push(media.media_url_https);
70
+ }
71
+ }
72
+
73
+ return entities;
74
+ }
75
+
76
+ /**
77
+ * @returns A Tweet object containing the tweet data
78
+ * @param data The raw tweet data from the response received from TwitterAPI
79
+ */
80
+ export function toTweet(data: RawTweet): Tweet {
81
+ return {
82
+ id: data.rest_id,
83
+ createdAt: data.legacy.created_at,
84
+ tweetBy: data.legacy.user_id_str,
85
+ entities: toTweetEntities(data.legacy.entities),
86
+ quoted: data.legacy.quoted_status_id_str,
87
+ fullText: Parsers.normalizeText(data.legacy.full_text),
88
+ replyTo: data.legacy.in_reply_to_status_id_str,
89
+ lang: data.legacy.lang,
90
+ quoteCount: data.legacy.quote_count,
91
+ replyCount: data.legacy.reply_count,
92
+ retweetCount: data.legacy.retweet_count,
93
+ likeCount: data.legacy.favorite_count
94
+ };
95
+ }