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.
- package/.eslintignore +3 -0
- package/.eslintrc.js +54 -0
- package/.github/workflows/documentation.yml +29 -9
- package/.github/workflows/publish.yml +8 -3
- package/.prettierignore +3 -0
- package/.prettierrc +13 -0
- package/README.md +59 -61
- package/dist/Rettiwt.d.ts +19 -0
- package/dist/Rettiwt.js +30 -0
- package/dist/Rettiwt.js.map +1 -0
- package/dist/enums/ApiErrors.d.ts +30 -0
- package/dist/enums/ApiErrors.js +35 -0
- package/dist/enums/ApiErrors.js.map +1 -0
- package/dist/enums/HTTP.d.ts +11 -11
- package/dist/enums/HTTP.js +15 -16
- package/dist/enums/HTTP.js.map +1 -1
- package/dist/helper/JsonUtils.d.ts +26 -0
- package/dist/helper/JsonUtils.js +88 -0
- package/dist/helper/JsonUtils.js.map +1 -0
- package/dist/index.d.ts +10 -43
- package/dist/index.js +16 -55
- package/dist/index.js.map +1 -1
- package/dist/models/CursoredData.d.ts +37 -0
- package/dist/models/CursoredData.js +59 -0
- package/dist/models/CursoredData.js.map +1 -0
- package/dist/models/{data/Tweet.d.ts → Tweet.d.ts} +4 -4
- package/dist/models/{data/Tweet.js → Tweet.js} +7 -32
- package/dist/models/Tweet.js.map +1 -0
- package/dist/models/{data/User.d.ts → User.d.ts} +3 -3
- package/dist/models/{data/User.js → User.js} +3 -3
- package/dist/models/User.js.map +1 -0
- package/dist/services/FetcherService.d.ts +66 -0
- package/dist/services/FetcherService.js +209 -0
- package/dist/services/FetcherService.js.map +1 -0
- package/dist/services/TweetService.d.ts +88 -0
- package/dist/services/TweetService.js +244 -0
- package/dist/services/TweetService.js.map +1 -0
- package/dist/services/UserService.d.ts +60 -0
- package/dist/services/UserService.js +188 -0
- package/dist/services/UserService.js.map +1 -0
- package/dist/types/{Service.d.ts → CursoredData.d.ts} +3 -3
- package/dist/types/CursoredData.js +3 -0
- package/dist/types/CursoredData.js.map +1 -0
- package/dist/types/Tweet.js +1 -1
- package/dist/types/User.js +1 -1
- package/package.json +15 -19
- package/src/Rettiwt.ts +33 -0
- package/src/enums/ApiErrors.ts +30 -0
- package/src/enums/HTTP.ts +12 -12
- package/src/helper/JsonUtils.ts +86 -0
- package/src/index.ts +14 -57
- package/src/models/CursoredData.ts +64 -0
- package/src/models/Tweet.ts +116 -0
- package/src/models/User.ts +72 -0
- package/src/services/FetcherService.ts +186 -0
- package/src/services/TweetService.ts +153 -0
- package/src/services/UserService.ts +117 -0
- package/src/types/CursoredData.ts +24 -0
- package/src/types/Tweet.ts +35 -35
- package/src/types/User.ts +30 -30
- package/tsconfig.json +9 -9
- package/dist/config/env.d.ts +0 -5
- package/dist/config/env.js +0 -9
- package/dist/config/env.js.map +0 -1
- package/dist/enums/Errors.d.ts +0 -21
- package/dist/enums/Errors.js +0 -29
- package/dist/enums/Errors.js.map +0 -1
- package/dist/graphql/enums/Errors.d.ts +0 -21
- package/dist/graphql/enums/Errors.js +0 -29
- package/dist/graphql/enums/Errors.js.map +0 -1
- package/dist/graphql/queries/RootQuery.d.ts +0 -4
- package/dist/graphql/queries/RootQuery.js +0 -83
- package/dist/graphql/queries/RootQuery.js.map +0 -1
- package/dist/graphql/resolvers/AccountResolver.d.ts +0 -12
- package/dist/graphql/resolvers/AccountResolver.js +0 -84
- package/dist/graphql/resolvers/AccountResolver.js.map +0 -1
- package/dist/graphql/resolvers/ResolverBase.d.ts +0 -16
- package/dist/graphql/resolvers/ResolverBase.js +0 -23
- package/dist/graphql/resolvers/ResolverBase.js.map +0 -1
- package/dist/graphql/resolvers/TweetResolver.d.ts +0 -46
- package/dist/graphql/resolvers/TweetResolver.js +0 -302
- package/dist/graphql/resolvers/TweetResolver.js.map +0 -1
- package/dist/graphql/resolvers/UserResolver.d.ts +0 -48
- package/dist/graphql/resolvers/UserResolver.js +0 -334
- package/dist/graphql/resolvers/UserResolver.js.map +0 -1
- package/dist/graphql/types/Global.d.ts +0 -4
- package/dist/graphql/types/Global.js +0 -13
- package/dist/graphql/types/Global.js.map +0 -1
- package/dist/graphql/types/TweetTypes.d.ts +0 -4
- package/dist/graphql/types/TweetTypes.js +0 -160
- package/dist/graphql/types/TweetTypes.js.map +0 -1
- package/dist/graphql/types/UserTypes.d.ts +0 -3
- package/dist/graphql/types/UserTypes.js +0 -137
- package/dist/graphql/types/UserTypes.js.map +0 -1
- package/dist/models/args/TweetListArgs.d.ts +0 -21
- package/dist/models/args/TweetListArgs.js +0 -54
- package/dist/models/args/TweetListArgs.js.map +0 -1
- package/dist/models/args/UserListArgs.d.ts +0 -21
- package/dist/models/args/UserListArgs.js +0 -54
- package/dist/models/args/UserListArgs.js.map +0 -1
- package/dist/models/auth/AuthCookie.d.ts +0 -21
- package/dist/models/auth/AuthCookie.js +0 -33
- package/dist/models/auth/AuthCookie.js.map +0 -1
- package/dist/models/data/CursoredData.d.ts +0 -34
- package/dist/models/data/CursoredData.js +0 -42
- package/dist/models/data/CursoredData.js.map +0 -1
- package/dist/models/data/Tweet.js.map +0 -1
- package/dist/models/data/User.js.map +0 -1
- package/dist/server.d.ts +0 -1
- package/dist/server.js +0 -76
- package/dist/server.js.map +0 -1
- package/dist/services/auth/AccountService.d.ts +0 -83
- package/dist/services/auth/AccountService.js +0 -412
- package/dist/services/auth/AccountService.js.map +0 -1
- package/dist/services/auth/AuthService.d.ts +0 -31
- package/dist/services/auth/AuthService.js +0 -118
- package/dist/services/auth/AuthService.js.map +0 -1
- package/dist/services/data/TweetService.d.ts +0 -60
- package/dist/services/data/TweetService.js +0 -250
- package/dist/services/data/TweetService.js.map +0 -1
- package/dist/services/data/UserService.d.ts +0 -71
- package/dist/services/data/UserService.js +0 -278
- package/dist/services/data/UserService.js.map +0 -1
- package/dist/services/helper/Headers.d.ts +0 -19
- package/dist/services/helper/Headers.js +0 -62
- package/dist/services/helper/Headers.js.map +0 -1
- package/dist/services/helper/Parser.d.ts +0 -22
- package/dist/services/helper/Parser.js +0 -84
- package/dist/services/helper/Parser.js.map +0 -1
- package/dist/services/helper/extractors/Tweets.d.ts +0 -23
- package/dist/services/helper/extractors/Tweets.js +0 -200
- package/dist/services/helper/extractors/Tweets.js.map +0 -1
- package/dist/services/helper/extractors/Users.d.ts +0 -17
- package/dist/services/helper/extractors/Users.js +0 -151
- package/dist/services/helper/extractors/Users.js.map +0 -1
- package/dist/services/helper/payloads/LoginFlows.d.ts +0 -77
- package/dist/services/helper/payloads/LoginFlows.js +0 -92
- package/dist/services/helper/payloads/LoginFlows.js.map +0 -1
- package/dist/services/helper/urls/Authentication.d.ts +0 -4
- package/dist/services/helper/urls/Authentication.js +0 -11
- package/dist/services/helper/urls/Authentication.js.map +0 -1
- package/dist/services/util/CacheService.d.ts +0 -33
- package/dist/services/util/CacheService.js +0 -96
- package/dist/services/util/CacheService.js.map +0 -1
- package/dist/services/util/FetcherService.d.ts +0 -65
- package/dist/services/util/FetcherService.js +0 -202
- package/dist/services/util/FetcherService.js.map +0 -1
- package/dist/types/Args.d.ts +0 -11
- package/dist/types/Args.js +0 -4
- package/dist/types/Args.js.map +0 -1
- package/dist/types/Authentication.d.ts +0 -55
- package/dist/types/Authentication.js +0 -6
- package/dist/types/Authentication.js.map +0 -1
- package/dist/types/Resolvers.d.ts +0 -15
- package/dist/types/Resolvers.js +0 -3
- package/dist/types/Resolvers.js.map +0 -1
- package/dist/types/Rettiwt.d.ts +0 -16
- package/dist/types/Rettiwt.js +0 -3
- package/dist/types/Rettiwt.js.map +0 -1
- package/dist/types/Service.js +0 -5
- package/dist/types/Service.js.map +0 -1
- package/docs/.nojekyll +0 -1
- package/docs/assets/highlight.css +0 -64
- package/docs/assets/main.js +0 -58
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1280
- package/docs/classes/AccountService.html +0 -286
- package/docs/classes/AuthCookie.html +0 -146
- package/docs/classes/AuthService.html +0 -147
- package/docs/classes/CacheService.html +0 -157
- package/docs/classes/Cursor.html +0 -102
- package/docs/classes/CursoredData.html +0 -126
- package/docs/classes/DataValidationError.html +0 -120
- package/docs/classes/FetcherService.html +0 -225
- package/docs/classes/Tweet.html +0 -210
- package/docs/classes/TweetEntities.html +0 -128
- package/docs/classes/TweetFilter.html +0 -233
- package/docs/classes/TweetListArgs.html +0 -118
- package/docs/classes/TweetService.html +0 -319
- package/docs/classes/User.html +0 -230
- package/docs/classes/UserListArgs.html +0 -118
- package/docs/classes/UserService.html +0 -355
- package/docs/enums/HttpMethods.html +0 -74
- package/docs/functions/Rettiwt.html +0 -100
- package/docs/index.html +0 -159
- package/docs/interfaces/IAuthCookie.html +0 -104
- package/docs/interfaces/ICursor.html +0 -77
- package/docs/interfaces/ICursoredData.html +0 -93
- package/docs/interfaces/IDataContext.html +0 -91
- package/docs/interfaces/IDataValidationError.html +0 -109
- package/docs/interfaces/IListArgs.html +0 -87
- package/docs/interfaces/ITweet.html +0 -176
- package/docs/interfaces/ITweetEntities.html +0 -104
- package/docs/interfaces/ITweetFilter.html +0 -158
- package/docs/interfaces/IUser.html +0 -194
- package/docs/modules.html +0 -111
- package/environment.d.ts +0 -11
- package/src/config/env.ts +0 -5
- package/src/enums/Errors.ts +0 -22
- package/src/graphql/enums/Errors.ts +0 -22
- package/src/graphql/queries/RootQuery.ts +0 -81
- package/src/graphql/resolvers/AccountResolver.ts +0 -22
- package/src/graphql/resolvers/ResolverBase.ts +0 -26
- package/src/graphql/resolvers/TweetResolver.ts +0 -225
- package/src/graphql/resolvers/UserResolver.ts +0 -257
- package/src/graphql/types/Global.ts +0 -10
- package/src/graphql/types/TweetTypes.ts +0 -158
- package/src/graphql/types/UserTypes.ts +0 -134
- package/src/models/args/TweetListArgs.ts +0 -47
- package/src/models/args/UserListArgs.ts +0 -47
- package/src/models/auth/AuthCookie.ts +0 -43
- package/src/models/data/CursoredData.ts +0 -45
- package/src/models/data/Tweet.ts +0 -118
- package/src/models/data/User.ts +0 -72
- package/src/server.ts +0 -37
- package/src/services/auth/AccountService.ts +0 -283
- package/src/services/auth/AuthService.ts +0 -81
- package/src/services/data/TweetService.ts +0 -197
- package/src/services/data/UserService.ts +0 -221
- package/src/services/helper/Headers.ts +0 -60
- package/src/services/helper/Parser.ts +0 -89
- package/src/services/helper/extractors/Tweets.ts +0 -190
- package/src/services/helper/extractors/Users.ts +0 -141
- package/src/services/helper/payloads/LoginFlows.ts +0 -90
- package/src/services/helper/urls/Authentication.ts +0 -6
- package/src/services/util/CacheService.ts +0 -76
- package/src/services/util/FetcherService.ts +0 -143
- package/src/types/Args.ts +0 -12
- package/src/types/Authentication.ts +0 -63
- package/src/types/Resolvers.ts +0 -18
- package/src/types/Rettiwt.ts +0 -20
- 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
|
+
}
|