rettiwt-api 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +1 -0
- package/README.md +39 -20
- package/dist/Rettiwt.d.ts +5 -5
- package/dist/Rettiwt.js +6 -7
- package/dist/Rettiwt.js.map +1 -1
- package/dist/enums/Logging.d.ts +12 -0
- package/dist/enums/Logging.js +17 -0
- package/dist/enums/Logging.js.map +1 -0
- package/dist/index.d.ts +15 -11
- package/dist/index.js +15 -11
- package/dist/index.js.map +1 -1
- package/dist/models/internal/RettiwtConfig.d.ts +20 -0
- package/dist/models/internal/RettiwtConfig.js +23 -0
- package/dist/models/internal/RettiwtConfig.js.map +1 -0
- package/dist/models/{CursoredData.d.ts → public/CursoredData.d.ts} +2 -3
- package/dist/models/{CursoredData.js → public/CursoredData.js} +1 -16
- package/dist/models/public/CursoredData.js.map +1 -0
- package/dist/models/{List.d.ts → public/List.d.ts} +1 -1
- package/dist/models/public/List.js.map +1 -0
- package/dist/models/{Tweet.d.ts → public/Tweet.d.ts} +1 -1
- package/dist/models/{Tweet.js → public/Tweet.js} +1 -1
- package/dist/models/public/Tweet.js.map +1 -0
- package/dist/models/{User.d.ts → public/User.d.ts} +1 -1
- package/dist/models/public/User.js.map +1 -0
- package/dist/services/{FetcherService.d.ts → internal/FetcherService.d.ts} +28 -9
- package/dist/services/{FetcherService.js → internal/FetcherService.js} +100 -22
- package/dist/services/internal/FetcherService.js.map +1 -0
- package/dist/services/internal/LogService.d.ts +22 -0
- package/dist/services/internal/LogService.js +35 -0
- package/dist/services/internal/LogService.js.map +1 -0
- package/dist/services/{TweetService.d.ts → public/TweetService.d.ts} +7 -7
- package/dist/services/{TweetService.js → public/TweetService.js} +4 -5
- package/dist/services/public/TweetService.js.map +1 -0
- package/dist/services/{UserService.d.ts → public/UserService.d.ts} +20 -7
- package/dist/services/{UserService.js → public/UserService.js} +35 -5
- package/dist/services/public/UserService.js.map +1 -0
- package/dist/types/internal/RettiwtConfig.d.ts +13 -0
- package/dist/types/internal/RettiwtConfig.js +3 -0
- package/dist/types/internal/RettiwtConfig.js.map +1 -0
- package/dist/types/public/CursoredData.js.map +1 -0
- package/dist/types/{List.js.map → public/List.js.map} +1 -1
- package/dist/types/{Tweet.js.map → public/Tweet.js.map} +1 -1
- package/dist/types/{User.js.map → public/User.js.map} +1 -1
- package/package.json +2 -2
- package/src/Rettiwt.ts +11 -9
- package/src/enums/Logging.ts +12 -0
- package/src/index.ts +15 -11
- package/src/models/internal/RettiwtConfig.ts +29 -0
- package/src/models/{CursoredData.ts → public/CursoredData.ts} +7 -22
- package/src/models/{List.ts → public/List.ts} +9 -9
- package/src/models/{Tweet.ts → public/Tweet.ts} +25 -25
- package/src/models/{User.ts → public/User.ts} +16 -16
- package/src/services/{FetcherService.ts → internal/FetcherService.ts} +116 -21
- package/src/services/internal/LogService.ts +39 -0
- package/src/services/{TweetService.ts → public/TweetService.ts} +16 -16
- package/src/services/{UserService.ts → public/UserService.ts} +39 -13
- package/src/types/internal/RettiwtConfig.ts +15 -0
- package/dist/models/CursoredData.js.map +0 -1
- package/dist/models/List.js.map +0 -1
- package/dist/models/Tweet.js.map +0 -1
- package/dist/models/User.js.map +0 -1
- package/dist/services/FetcherService.js.map +0 -1
- package/dist/services/TweetService.js.map +0 -1
- package/dist/services/UserService.js.map +0 -1
- package/dist/types/CursoredData.js.map +0 -1
- /package/dist/models/{List.js → public/List.js} +0 -0
- /package/dist/models/{User.js → public/User.js} +0 -0
- /package/dist/types/{CursoredData.d.ts → public/CursoredData.d.ts} +0 -0
- /package/dist/types/{CursoredData.js → public/CursoredData.js} +0 -0
- /package/dist/types/{List.d.ts → public/List.d.ts} +0 -0
- /package/dist/types/{List.js → public/List.js} +0 -0
- /package/dist/types/{Tweet.d.ts → public/Tweet.d.ts} +0 -0
- /package/dist/types/{Tweet.js → public/Tweet.js} +0 -0
- /package/dist/types/{User.d.ts → public/User.d.ts} +0 -0
- /package/dist/types/{User.js → public/User.js} +0 -0
- /package/src/types/{CursoredData.ts → public/CursoredData.ts} +0 -0
- /package/src/types/{List.ts → public/List.ts} +0 -0
- /package/src/types/{Tweet.ts → public/Tweet.ts} +0 -0
- /package/src/types/{User.ts → public/User.ts} +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// TYPES
|
|
2
|
+
import { IRettiwtConfig } from '../../types/internal/RettiwtConfig';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The configuration for initializing a new Rettiwt instance.
|
|
6
|
+
*
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export class RettiwtConfig implements IRettiwtConfig {
|
|
10
|
+
/** The apiKey (cookie) to use for authenticating Rettiwt against Twitter API. */
|
|
11
|
+
public apiKey?: string;
|
|
12
|
+
|
|
13
|
+
/** Optional URL with proxy configuration to use for requests to Twitter API. */
|
|
14
|
+
public proxyUrl?: URL;
|
|
15
|
+
|
|
16
|
+
/** Whether to write logs to console or not. */
|
|
17
|
+
public logging?: boolean;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Initializes a new configuration object from the given config.
|
|
21
|
+
*
|
|
22
|
+
* @param config - The configuration object.
|
|
23
|
+
*/
|
|
24
|
+
public constructor(config: RettiwtConfig) {
|
|
25
|
+
this.apiKey = config.apiKey;
|
|
26
|
+
this.proxyUrl = config.proxyUrl;
|
|
27
|
+
this.logging = config.logging;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
// PACKAGES
|
|
2
|
-
import { ITweet as IRawTweet, IUser as IRawUser } from 'rettiwt-core';
|
|
3
|
-
|
|
4
1
|
// MODELS
|
|
5
2
|
import { Tweet } from './Tweet';
|
|
6
3
|
import { User } from './User';
|
|
7
4
|
|
|
8
5
|
// TYPES
|
|
9
|
-
import { ICursor, ICursoredData } from '
|
|
6
|
+
import { ICursor, ICursoredData } from '../../types/public/CursoredData';
|
|
10
7
|
|
|
11
8
|
/**
|
|
12
9
|
* The data that us fetched batch-wise along with a cursor.
|
|
@@ -17,29 +14,17 @@ import { ICursor, ICursoredData } from '../types/CursoredData';
|
|
|
17
14
|
*/
|
|
18
15
|
export class CursoredData<T extends Tweet | User> implements ICursoredData<T> {
|
|
19
16
|
/** The list of data of the given type. */
|
|
20
|
-
list: T[] = [];
|
|
17
|
+
public list: T[] = [];
|
|
21
18
|
|
|
22
19
|
/** The cursor to the next batch of data. */
|
|
23
|
-
next: Cursor;
|
|
20
|
+
public next: Cursor;
|
|
24
21
|
|
|
25
22
|
/**
|
|
26
23
|
* @param list - The list of data item to store.
|
|
27
24
|
* @param next - The cursor to the next batch of data.
|
|
28
25
|
*/
|
|
29
|
-
constructor(list:
|
|
30
|
-
|
|
31
|
-
for (const item of list) {
|
|
32
|
-
// If the item is a valid raw tweet
|
|
33
|
-
if (item.__typename == 'Tweet' && item.rest_id) {
|
|
34
|
-
this.list.push(new Tweet(item as IRawTweet) as T);
|
|
35
|
-
}
|
|
36
|
-
// If the item is a valid raw user
|
|
37
|
-
else if (item.__typename == 'User' && item.rest_id && (item as IRawUser).id) {
|
|
38
|
-
this.list.push(new User(item as IRawUser) as T);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Initializing cursors
|
|
26
|
+
public constructor(list: T[] = [], next: string = '') {
|
|
27
|
+
this.list = list;
|
|
43
28
|
this.next = new Cursor(next);
|
|
44
29
|
}
|
|
45
30
|
}
|
|
@@ -51,14 +36,14 @@ export class CursoredData<T extends Tweet | User> implements ICursoredData<T> {
|
|
|
51
36
|
*/
|
|
52
37
|
export class Cursor implements ICursor {
|
|
53
38
|
/** The cursor string. */
|
|
54
|
-
value: string;
|
|
39
|
+
public value: string;
|
|
55
40
|
|
|
56
41
|
/**
|
|
57
42
|
* Initializes a new cursor from the given cursor string.
|
|
58
43
|
*
|
|
59
44
|
* @param cursorStr - The string representation of the cursor.
|
|
60
45
|
*/
|
|
61
|
-
constructor(cursorStr: string) {
|
|
46
|
+
public constructor(cursorStr: string) {
|
|
62
47
|
this.value = cursorStr;
|
|
63
48
|
}
|
|
64
49
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { IList as IRawList } from 'rettiwt-core';
|
|
3
3
|
|
|
4
4
|
// TYPES
|
|
5
|
-
import { IList } from '
|
|
5
|
+
import { IList } from '../../types/public/List';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* The details of a single Twitter List.
|
|
@@ -11,32 +11,32 @@ import { IList } from '../types/List';
|
|
|
11
11
|
*/
|
|
12
12
|
export class List implements IList {
|
|
13
13
|
/** The rest id of the list. */
|
|
14
|
-
id: string;
|
|
14
|
+
public id: string;
|
|
15
15
|
|
|
16
16
|
/** The name of the list. */
|
|
17
|
-
name: string;
|
|
17
|
+
public name: string;
|
|
18
18
|
|
|
19
19
|
/** The date and time of creation of the list, int UTC string format. */
|
|
20
|
-
createdAt: string;
|
|
20
|
+
public createdAt: string;
|
|
21
21
|
|
|
22
22
|
/** The list description. */
|
|
23
|
-
description: string;
|
|
23
|
+
public description: string;
|
|
24
24
|
|
|
25
25
|
/** The number of memeber of the list. */
|
|
26
|
-
memberCount: number;
|
|
26
|
+
public memberCount: number;
|
|
27
27
|
|
|
28
28
|
/** The number of subscribers of the list. */
|
|
29
|
-
subscriberCount: number;
|
|
29
|
+
public subscriberCount: number;
|
|
30
30
|
|
|
31
31
|
/** The rest id of the user who created the list. */
|
|
32
|
-
createdBy: string;
|
|
32
|
+
public createdBy: string;
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Initializes a new Tweet List from the given raw list data.
|
|
36
36
|
*
|
|
37
37
|
* @param list - list The raw tweet list data.
|
|
38
38
|
*/
|
|
39
|
-
constructor(list: IRawList) {
|
|
39
|
+
public constructor(list: IRawList) {
|
|
40
40
|
this.id = list.id_str;
|
|
41
41
|
this.name = list.name;
|
|
42
42
|
this.createdAt = new Date(list.created_at).toISOString();
|
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
} from 'rettiwt-core';
|
|
8
8
|
|
|
9
9
|
// TYPES
|
|
10
|
-
import { ITweet, ITweetEntities } from '
|
|
10
|
+
import { ITweet, ITweetEntities } from '../../types/public/Tweet';
|
|
11
11
|
|
|
12
12
|
// MODELS
|
|
13
13
|
import { User } from './User';
|
|
14
14
|
|
|
15
15
|
// PARSERS
|
|
16
|
-
import { normalizeText } from '
|
|
16
|
+
import { normalizeText } from '../../helper/JsonUtils';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* The details of a single Tweet.
|
|
@@ -22,56 +22,56 @@ import { normalizeText } from '../helper/JsonUtils';
|
|
|
22
22
|
*/
|
|
23
23
|
export class Tweet implements ITweet {
|
|
24
24
|
/** The rest id of the tweet. */
|
|
25
|
-
id: string;
|
|
25
|
+
public id: string;
|
|
26
26
|
|
|
27
27
|
/** The details of the user who made the tweet. */
|
|
28
|
-
tweetBy: User;
|
|
28
|
+
public tweetBy: User;
|
|
29
29
|
|
|
30
30
|
/** The date and time of creation of the tweet, in UTC string format. */
|
|
31
|
-
createdAt: string;
|
|
31
|
+
public createdAt: string;
|
|
32
32
|
|
|
33
33
|
/** Additional tweet entities like urls, mentions, etc. */
|
|
34
|
-
entities: TweetEntities;
|
|
34
|
+
public entities: TweetEntities;
|
|
35
35
|
|
|
36
36
|
/** The urls of the media contents of the tweet (if any). */
|
|
37
|
-
media: TweetMedia[];
|
|
37
|
+
public media: TweetMedia[];
|
|
38
38
|
|
|
39
39
|
/** The rest id of the tweet which is quoted in the tweet. */
|
|
40
|
-
quoted: string;
|
|
40
|
+
public quoted: string;
|
|
41
41
|
|
|
42
42
|
/** The full text content of the tweet. */
|
|
43
|
-
fullText: string;
|
|
43
|
+
public fullText: string;
|
|
44
44
|
|
|
45
45
|
/** The rest id of the user to which the tweet is a reply. */
|
|
46
|
-
replyTo: string;
|
|
46
|
+
public replyTo: string;
|
|
47
47
|
|
|
48
48
|
/** The language in which the tweet is written. */
|
|
49
|
-
lang: string;
|
|
49
|
+
public lang: string;
|
|
50
50
|
|
|
51
51
|
/** The number of quotes of the tweet. */
|
|
52
|
-
quoteCount: number;
|
|
52
|
+
public quoteCount: number;
|
|
53
53
|
|
|
54
54
|
/** The number of replies to the tweet. */
|
|
55
|
-
replyCount: number;
|
|
55
|
+
public replyCount: number;
|
|
56
56
|
|
|
57
57
|
/** The number of retweets of the tweet. */
|
|
58
|
-
retweetCount: number;
|
|
58
|
+
public retweetCount: number;
|
|
59
59
|
|
|
60
60
|
/** The number of likes of the tweet. */
|
|
61
|
-
likeCount: number;
|
|
61
|
+
public likeCount: number;
|
|
62
62
|
|
|
63
63
|
/** The number of views of a tweet. */
|
|
64
|
-
viewCount: number;
|
|
64
|
+
public viewCount: number;
|
|
65
65
|
|
|
66
66
|
/** The number of bookmarks of a tweet. */
|
|
67
|
-
bookmarkCount: number;
|
|
67
|
+
public bookmarkCount: number;
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* Initializes a new Tweet from the given raw tweet data.
|
|
71
71
|
*
|
|
72
72
|
* @param tweet - The raw tweet data.
|
|
73
73
|
*/
|
|
74
|
-
constructor(tweet: IRawTweet) {
|
|
74
|
+
public constructor(tweet: IRawTweet) {
|
|
75
75
|
this.id = tweet.rest_id;
|
|
76
76
|
this.createdAt = tweet.legacy.created_at;
|
|
77
77
|
this.tweetBy = new User(tweet.core.user_results.result);
|
|
@@ -97,20 +97,20 @@ export class Tweet implements ITweet {
|
|
|
97
97
|
*/
|
|
98
98
|
export class TweetEntities implements ITweetEntities {
|
|
99
99
|
/** The list of hashtags mentioned in the tweet. */
|
|
100
|
-
hashtags: string[] = [];
|
|
100
|
+
public hashtags: string[] = [];
|
|
101
101
|
|
|
102
102
|
/** The list of urls mentioned in the tweet. */
|
|
103
|
-
urls: string[] = [];
|
|
103
|
+
public urls: string[] = [];
|
|
104
104
|
|
|
105
105
|
/** The list of IDs of users mentioned in the tweet. */
|
|
106
|
-
mentionedUsers: string[] = [];
|
|
106
|
+
public mentionedUsers: string[] = [];
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* Initializes the TweetEntities from the raw tweet entities.
|
|
110
110
|
*
|
|
111
111
|
* @param entities - The raw tweet entities.
|
|
112
112
|
*/
|
|
113
|
-
constructor(entities: IRawTweetEntities) {
|
|
113
|
+
public constructor(entities: IRawTweetEntities) {
|
|
114
114
|
// Extracting user mentions
|
|
115
115
|
if (entities.user_mentions) {
|
|
116
116
|
for (const user of entities.user_mentions) {
|
|
@@ -141,17 +141,17 @@ export class TweetEntities implements ITweetEntities {
|
|
|
141
141
|
*/
|
|
142
142
|
export class TweetMedia {
|
|
143
143
|
/** The type of media. */
|
|
144
|
-
type: EMediaType;
|
|
144
|
+
public type: EMediaType;
|
|
145
145
|
|
|
146
146
|
/** The direct URL to the media. */
|
|
147
|
-
url: string = '';
|
|
147
|
+
public url: string = '';
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
150
|
* Initializes the TweetMedia from the raw tweet media.
|
|
151
151
|
*
|
|
152
152
|
* @param media - The raw tweet media.
|
|
153
153
|
*/
|
|
154
|
-
constructor(media: IRawExtendedMedia) {
|
|
154
|
+
public constructor(media: IRawExtendedMedia) {
|
|
155
155
|
this.type = media.type;
|
|
156
156
|
|
|
157
157
|
// If the media is a photo
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { IUser as IRawUser } from 'rettiwt-core';
|
|
3
3
|
|
|
4
4
|
// TYPES
|
|
5
|
-
import { IUser } from '
|
|
5
|
+
import { IUser } from '../../types/public/User';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* The details of a single user.
|
|
@@ -11,53 +11,53 @@ import { IUser } from '../types/User';
|
|
|
11
11
|
*/
|
|
12
12
|
export class User implements IUser {
|
|
13
13
|
/** The rest id of the user. */
|
|
14
|
-
id: string;
|
|
14
|
+
public id: string;
|
|
15
15
|
|
|
16
16
|
/** The username/screenname of the user. */
|
|
17
|
-
userName: string;
|
|
17
|
+
public userName: string;
|
|
18
18
|
|
|
19
19
|
/** The full name of the user. */
|
|
20
|
-
fullName: string;
|
|
20
|
+
public fullName: string;
|
|
21
21
|
|
|
22
22
|
/** The creation date of user's account. */
|
|
23
|
-
createdAt: string;
|
|
23
|
+
public createdAt: string;
|
|
24
24
|
|
|
25
25
|
/** The user's description. */
|
|
26
|
-
description: string;
|
|
26
|
+
public description: string;
|
|
27
27
|
|
|
28
28
|
/** Whether the account is verified or not. */
|
|
29
|
-
isVerified: boolean;
|
|
29
|
+
public isVerified: boolean;
|
|
30
30
|
|
|
31
31
|
/** The number of tweets liked by the user. */
|
|
32
|
-
favouritesCount: number;
|
|
32
|
+
public favouritesCount: number;
|
|
33
33
|
|
|
34
34
|
/** The number of followers of the user. */
|
|
35
|
-
followersCount: number;
|
|
35
|
+
public followersCount: number;
|
|
36
36
|
|
|
37
37
|
/** The number of following of the user. */
|
|
38
|
-
followingsCount: number;
|
|
38
|
+
public followingsCount: number;
|
|
39
39
|
|
|
40
40
|
/** The number of tweets made by the user. */
|
|
41
|
-
statusesCount: number;
|
|
41
|
+
public statusesCount: number;
|
|
42
42
|
|
|
43
43
|
/** The location of user as provided by user. */
|
|
44
|
-
location: string;
|
|
44
|
+
public location: string;
|
|
45
45
|
|
|
46
46
|
/** The rest id of the tweet pinned in the user's profile. */
|
|
47
|
-
pinnedTweet: string;
|
|
47
|
+
public pinnedTweet: string;
|
|
48
48
|
|
|
49
49
|
/** The url of the profile banner image. */
|
|
50
|
-
profileBanner: string;
|
|
50
|
+
public profileBanner: string;
|
|
51
51
|
|
|
52
52
|
/** The url of the profile image. */
|
|
53
|
-
profileImage: string;
|
|
53
|
+
public profileImage: string;
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Initializes a new User from the given raw user data.
|
|
57
57
|
*
|
|
58
58
|
* @param user - The raw user data.
|
|
59
59
|
*/
|
|
60
|
-
constructor(user: IRawUser) {
|
|
60
|
+
public constructor(user: IRawUser) {
|
|
61
61
|
this.id = user.rest_id;
|
|
62
62
|
this.userName = user.legacy.screen_name;
|
|
63
63
|
this.fullName = user.legacy.name;
|
|
@@ -13,20 +13,25 @@ import {
|
|
|
13
13
|
} from 'rettiwt-core';
|
|
14
14
|
import axios, { AxiosRequestConfig, AxiosRequestHeaders, AxiosResponse } from 'axios';
|
|
15
15
|
import https, { Agent } from 'https';
|
|
16
|
-
import { AuthCredential } from 'rettiwt-auth';
|
|
16
|
+
import { AuthCredential, Auth } from 'rettiwt-auth';
|
|
17
17
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
18
18
|
|
|
19
|
+
// SERVICES
|
|
20
|
+
import { LogService } from './LogService';
|
|
21
|
+
|
|
19
22
|
// ENUMS
|
|
20
|
-
import { EHttpStatus } from '
|
|
21
|
-
import { EApiErrors } from '
|
|
23
|
+
import { EHttpStatus } from '../../enums/HTTP';
|
|
24
|
+
import { EApiErrors } from '../../enums/ApiErrors';
|
|
25
|
+
import { ELogActions } from '../../enums/Logging';
|
|
22
26
|
|
|
23
27
|
// MODELS
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
28
|
+
import { RettiwtConfig } from '../../models/internal/RettiwtConfig';
|
|
29
|
+
import { CursoredData } from '../../models/public/CursoredData';
|
|
30
|
+
import { Tweet } from '../../models/public/Tweet';
|
|
31
|
+
import { User } from '../../models/public/User';
|
|
27
32
|
|
|
28
33
|
// HELPERS
|
|
29
|
-
import { findByFilter, findKeyByValue } from '
|
|
34
|
+
import { findByFilter, findKeyByValue } from '../../helper/JsonUtils';
|
|
30
35
|
|
|
31
36
|
/**
|
|
32
37
|
* The base service that handles all HTTP requests.
|
|
@@ -35,18 +40,25 @@ import { findByFilter, findKeyByValue } from '../helper/JsonUtils';
|
|
|
35
40
|
*/
|
|
36
41
|
export class FetcherService {
|
|
37
42
|
/** The credential to use for authenticating against Twitter API. */
|
|
38
|
-
private cred
|
|
43
|
+
private cred?: AuthCredential;
|
|
44
|
+
|
|
45
|
+
/** Whether the instance is authenticated or not. */
|
|
46
|
+
private readonly isAuthenticated: boolean;
|
|
39
47
|
|
|
40
48
|
/** The HTTPS Agent to use for requests to Twitter API. */
|
|
41
49
|
private readonly httpsAgent: Agent;
|
|
42
50
|
|
|
51
|
+
/** The log service instance to use to logging. */
|
|
52
|
+
private readonly logger: LogService;
|
|
53
|
+
|
|
43
54
|
/**
|
|
44
|
-
* @param
|
|
45
|
-
* @param proxyUrl - Optional URL with proxy configuration to use for requests to Twitter API.
|
|
55
|
+
* @param config - The config object for configuring the Rettiwt instance.
|
|
46
56
|
*/
|
|
47
|
-
constructor(
|
|
48
|
-
this.cred = this.getAuthCredential(apiKey);
|
|
49
|
-
this.
|
|
57
|
+
public constructor(config?: RettiwtConfig) {
|
|
58
|
+
this.cred = config?.apiKey ? this.getAuthCredential(config.apiKey) : undefined;
|
|
59
|
+
this.isAuthenticated = config?.apiKey ? true : false;
|
|
60
|
+
this.httpsAgent = this.getHttpsAgent(config?.proxyUrl);
|
|
61
|
+
this.logger = new LogService(config?.logging);
|
|
50
62
|
}
|
|
51
63
|
|
|
52
64
|
/**
|
|
@@ -59,6 +71,27 @@ export class FetcherService {
|
|
|
59
71
|
return new AuthCredential(apiKey.split(';'));
|
|
60
72
|
}
|
|
61
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Checks the authorization status based on the requested resource.
|
|
76
|
+
*
|
|
77
|
+
* @param resourceType - The type of resource to fetch.
|
|
78
|
+
* @throws An error if not authorized to access the requested resource.
|
|
79
|
+
*/
|
|
80
|
+
private checkAuthorization(resourceType: EResourceType): void {
|
|
81
|
+
// Logging
|
|
82
|
+
this.logger.log(ELogActions.AUTHORIZATION, { authenticated: this.isAuthenticated });
|
|
83
|
+
|
|
84
|
+
// Checking authorization status
|
|
85
|
+
if (
|
|
86
|
+
resourceType != EResourceType.TWEET_DETAILS &&
|
|
87
|
+
resourceType != EResourceType.USER_DETAILS &&
|
|
88
|
+
resourceType != EResourceType.USER_TWEETS &&
|
|
89
|
+
this.isAuthenticated == false
|
|
90
|
+
) {
|
|
91
|
+
throw new Error(EApiErrors.RESOURCE_NOT_ALLOWED);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
62
95
|
/**
|
|
63
96
|
* Gets the HttpsAgent based on whether a proxy is used or not.
|
|
64
97
|
*
|
|
@@ -78,6 +111,7 @@ export class FetcherService {
|
|
|
78
111
|
*
|
|
79
112
|
* @param res - The response object received.
|
|
80
113
|
* @returns The received response, if no HTTP errors are found.
|
|
114
|
+
* @throws An error if any HTTP-related error has occured.
|
|
81
115
|
*/
|
|
82
116
|
private handleHttpError(res: AxiosResponse<IResponse<unknown>>): AxiosResponse<IResponse<unknown>> {
|
|
83
117
|
/**
|
|
@@ -95,6 +129,7 @@ export class FetcherService {
|
|
|
95
129
|
*
|
|
96
130
|
* @param res - The response object received.
|
|
97
131
|
* @returns The received response, if no API errors are found.
|
|
132
|
+
* @throws An error if any API-related error has occured.
|
|
98
133
|
*/
|
|
99
134
|
private handleApiError(res: AxiosResponse<IResponse<unknown>>): AxiosResponse<IResponse<unknown>> {
|
|
100
135
|
// If error exists
|
|
@@ -121,6 +156,12 @@ export class FetcherService {
|
|
|
121
156
|
* @returns The response received.
|
|
122
157
|
*/
|
|
123
158
|
private async request(config: Request): Promise<AxiosResponse<IResponse<unknown>>> {
|
|
159
|
+
// Checking authorization for the requested resource
|
|
160
|
+
this.checkAuthorization(config.endpoint);
|
|
161
|
+
|
|
162
|
+
// If not authenticated, use guest authentication
|
|
163
|
+
this.cred = this.cred ?? (await new Auth().getGuestCredential());
|
|
164
|
+
|
|
124
165
|
/**
|
|
125
166
|
* Creating axios request configuration from the input configuration.
|
|
126
167
|
*/
|
|
@@ -145,14 +186,18 @@ export class FetcherService {
|
|
|
145
186
|
*
|
|
146
187
|
* @param data - The data from which extraction is to be done.
|
|
147
188
|
* @param type - The type of data to extract.
|
|
148
|
-
* @typeParam BaseType - The base type of the raw data present in the input.
|
|
149
|
-
* @typeParam DeserializedType - The type of data produced after deserialization of BaseType.
|
|
150
189
|
* @returns The extracted data.
|
|
151
190
|
*/
|
|
152
|
-
private extractData
|
|
191
|
+
private extractData(
|
|
153
192
|
data: NonNullable<unknown>,
|
|
154
193
|
type: EResourceType,
|
|
155
|
-
):
|
|
194
|
+
): {
|
|
195
|
+
/** The required extracted data. */
|
|
196
|
+
required: (IRawTweet | IRawUser)[];
|
|
197
|
+
|
|
198
|
+
/** The cursor string to the next batch of data. */
|
|
199
|
+
next: string;
|
|
200
|
+
} {
|
|
156
201
|
/**
|
|
157
202
|
* The required extracted data.
|
|
158
203
|
*/
|
|
@@ -166,7 +211,8 @@ export class FetcherService {
|
|
|
166
211
|
type == EResourceType.TWEET_SEARCH ||
|
|
167
212
|
type == EResourceType.USER_LIKES ||
|
|
168
213
|
type == EResourceType.LIST_TWEETS ||
|
|
169
|
-
type == EResourceType.USER_TWEETS
|
|
214
|
+
type == EResourceType.USER_TWEETS ||
|
|
215
|
+
type == EResourceType.USER_TWEETS_AND_REPLIES
|
|
170
216
|
) {
|
|
171
217
|
required = findByFilter<ITimelineTweet>(data, '__typename', 'TimelineTweet').map(
|
|
172
218
|
(item) => item.tweet_results.result,
|
|
@@ -182,7 +228,47 @@ export class FetcherService {
|
|
|
182
228
|
);
|
|
183
229
|
}
|
|
184
230
|
|
|
185
|
-
return
|
|
231
|
+
return {
|
|
232
|
+
required: required,
|
|
233
|
+
next: findByFilter<IRawCursor>(data, 'cursorType', 'Bottom')[0]?.value,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Deserializes the extracted data into a cursored list.
|
|
239
|
+
*
|
|
240
|
+
* @param extractedData - The list of extracted data.
|
|
241
|
+
* @param next - The cursor to the next batch of data.
|
|
242
|
+
* @returns The cursored data object.
|
|
243
|
+
*/
|
|
244
|
+
private deserializeData<OutType extends Tweet | User>(
|
|
245
|
+
extractedData: (IRawTweet | IRawUser)[] = [],
|
|
246
|
+
next: string = '',
|
|
247
|
+
): CursoredData<OutType> {
|
|
248
|
+
/** The list of deserialized data. */
|
|
249
|
+
const deserializedList: OutType[] = [];
|
|
250
|
+
|
|
251
|
+
// Deserializing the extracted raw data and storing it in the list
|
|
252
|
+
for (const item of extractedData) {
|
|
253
|
+
// If the item is a valid raw tweet
|
|
254
|
+
if (item && item.__typename == 'Tweet' && item.rest_id) {
|
|
255
|
+
// Logging
|
|
256
|
+
this.logger.log(ELogActions.DESERIALIZE, { type: item.__typename, id: item.rest_id });
|
|
257
|
+
|
|
258
|
+
// Adding deserialized Tweet to list
|
|
259
|
+
deserializedList.push(new Tweet(item as IRawTweet) as OutType);
|
|
260
|
+
}
|
|
261
|
+
// If the item is a valid raw user
|
|
262
|
+
else if (item && item.__typename == 'User' && item.rest_id && (item as IRawUser).id) {
|
|
263
|
+
// Logging
|
|
264
|
+
this.logger.log(ELogActions.DESERIALIZE, { type: item.__typename, id: item.rest_id });
|
|
265
|
+
|
|
266
|
+
// Adding deserialized User to list
|
|
267
|
+
deserializedList.push(new User(item as IRawUser) as OutType);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return new CursoredData<OutType>(deserializedList, next);
|
|
186
272
|
}
|
|
187
273
|
|
|
188
274
|
/**
|
|
@@ -197,6 +283,9 @@ export class FetcherService {
|
|
|
197
283
|
resourceType: EResourceType,
|
|
198
284
|
args: Args,
|
|
199
285
|
): Promise<CursoredData<OutType>> {
|
|
286
|
+
// Logging
|
|
287
|
+
this.logger.log(ELogActions.FETCH, { resourceType: resourceType, args: args });
|
|
288
|
+
|
|
200
289
|
// Preparing the HTTP request
|
|
201
290
|
const request: Request = new Request(resourceType, args);
|
|
202
291
|
|
|
@@ -204,9 +293,12 @@ export class FetcherService {
|
|
|
204
293
|
const res = await this.request(request).then((res) => res.data);
|
|
205
294
|
|
|
206
295
|
// Extracting data
|
|
207
|
-
const
|
|
296
|
+
const extractedData = this.extractData(res, resourceType);
|
|
297
|
+
|
|
298
|
+
// Deserializing data
|
|
299
|
+
const deserializedData = this.deserializeData<OutType>(extractedData.required, extractedData.next);
|
|
208
300
|
|
|
209
|
-
return
|
|
301
|
+
return deserializedData;
|
|
210
302
|
}
|
|
211
303
|
|
|
212
304
|
/**
|
|
@@ -217,6 +309,9 @@ export class FetcherService {
|
|
|
217
309
|
* @returns Whether posting was successful or not.
|
|
218
310
|
*/
|
|
219
311
|
protected async post(resourceType: EResourceType, args: Args): Promise<boolean> {
|
|
312
|
+
// Logging
|
|
313
|
+
this.logger.log(ELogActions.POST, { resourceType: resourceType, args: args });
|
|
314
|
+
|
|
220
315
|
// Preparing the HTTP request
|
|
221
316
|
const request: Request = new Request(resourceType, args);
|
|
222
317
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// ENUMS
|
|
2
|
+
import { ELogActions } from '../../enums/Logging';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handles logging of data for debug purpose.
|
|
6
|
+
*
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export class LogService {
|
|
10
|
+
/** Whether logging is enabled or not. */
|
|
11
|
+
private readonly enabled: boolean;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Initializes a new LogService instance.
|
|
15
|
+
*
|
|
16
|
+
* @param enable - Whether to enable logging or not.
|
|
17
|
+
*/
|
|
18
|
+
public constructor(enable?: boolean) {
|
|
19
|
+
this.enabled = enable ?? false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Logs the given data.
|
|
24
|
+
*
|
|
25
|
+
* @param data - The data to be logged.
|
|
26
|
+
*/
|
|
27
|
+
public log(action: ELogActions, data: NonNullable<unknown>): void {
|
|
28
|
+
// Proceed to log only if logging is enabled
|
|
29
|
+
if (this.enabled) {
|
|
30
|
+
// Preparing the log message
|
|
31
|
+
const logMessage: string = `[Rettiwt-API] [${action}] [${new Date().toISOString()}] ${JSON.stringify(
|
|
32
|
+
data,
|
|
33
|
+
)}`;
|
|
34
|
+
|
|
35
|
+
// Logging
|
|
36
|
+
console.log(logMessage);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|