rettiwt-api 5.1.0-alpha.0 → 6.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/.eslintrc.js +13 -8
- package/README.md +8 -1
- package/dist/cli.js +17 -14
- package/dist/cli.js.map +1 -1
- package/dist/collections/Extractors.d.ts +1 -1
- package/dist/collections/Extractors.js +21 -21
- package/dist/collections/Extractors.js.map +1 -1
- package/dist/collections/Groups.d.ts +4 -4
- package/dist/collections/Groups.js +45 -45
- package/dist/collections/Groups.js.map +1 -1
- package/dist/collections/Requests.d.ts +3 -3
- package/dist/collections/Requests.js +3 -3
- package/dist/collections/Requests.js.map +1 -1
- package/dist/collections/Tweet.d.ts +4 -4
- package/dist/collections/Tweet.js +5 -5
- package/dist/collections/Tweet.js.map +1 -1
- package/dist/commands/Tweet.js +32 -4
- package/dist/commands/Tweet.js.map +1 -1
- package/dist/enums/Api.d.ts +1 -1
- package/dist/enums/Api.js +7 -7
- package/dist/enums/Api.js.map +1 -1
- package/dist/enums/Authentication.d.ts +1 -1
- package/dist/enums/Authentication.js +7 -7
- package/dist/enums/Authentication.js.map +1 -1
- package/dist/enums/Data.d.ts +1 -1
- package/dist/enums/Data.js +7 -7
- package/dist/enums/Data.js.map +1 -1
- package/dist/enums/Logging.d.ts +1 -1
- package/dist/enums/Logging.js +11 -11
- package/dist/enums/Logging.js.map +1 -1
- package/dist/enums/Media.d.ts +1 -1
- package/dist/enums/Media.js +7 -7
- package/dist/enums/Media.js.map +1 -1
- package/dist/enums/Notification.d.ts +1 -1
- package/dist/enums/Notification.js +9 -9
- package/dist/enums/Notification.js.map +1 -1
- package/dist/enums/Resource.d.ts +1 -1
- package/dist/enums/Resource.js +42 -42
- package/dist/enums/Resource.js.map +1 -1
- package/dist/enums/Tweet.d.ts +1 -1
- package/dist/enums/Tweet.js +7 -7
- package/dist/enums/Tweet.js.map +1 -1
- package/dist/enums/raw/Analytics.d.ts +2 -2
- package/dist/enums/raw/Analytics.js +21 -21
- package/dist/enums/raw/Analytics.js.map +1 -1
- package/dist/enums/raw/Media.d.ts +1 -1
- package/dist/enums/raw/Media.js +7 -7
- package/dist/enums/raw/Media.js.map +1 -1
- package/dist/enums/raw/Notification.d.ts +1 -1
- package/dist/enums/raw/Notification.js +8 -8
- package/dist/enums/raw/Notification.js.map +1 -1
- package/dist/enums/raw/Tweet.d.ts +2 -2
- package/dist/enums/raw/Tweet.js +12 -12
- package/dist/enums/raw/Tweet.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/models/RettiwtConfig.d.ts +3 -4
- package/dist/models/RettiwtConfig.js +7 -7
- package/dist/models/RettiwtConfig.js.map +1 -1
- package/dist/models/args/FetchArgs.d.ts +3 -3
- package/dist/models/args/FetchArgs.js +3 -3
- package/dist/models/args/FetchArgs.js.map +1 -1
- package/dist/models/auth/AuthCredential.d.ts +2 -2
- package/dist/models/auth/AuthCredential.js +3 -3
- package/dist/models/auth/AuthCredential.js.map +1 -1
- package/dist/models/data/CursoredData.d.ts +2 -2
- package/dist/models/data/CursoredData.js +3 -3
- package/dist/models/data/CursoredData.js.map +1 -1
- package/dist/models/data/Notification.d.ts +2 -2
- package/dist/models/data/Notification.js +3 -3
- package/dist/models/data/Notification.js.map +1 -1
- package/dist/models/data/Tweet.d.ts +4 -4
- package/dist/models/data/Tweet.js +18 -18
- package/dist/models/data/Tweet.js.map +1 -1
- package/dist/models/data/User.js +9 -9
- package/dist/models/data/User.js.map +1 -1
- package/dist/requests/Tweet.d.ts +2 -2
- package/dist/requests/Tweet.js +2 -2
- package/dist/requests/Tweet.js.map +1 -1
- package/dist/requests/User.d.ts +2 -2
- package/dist/requests/User.js.map +1 -1
- package/dist/services/internal/AuthService.js +1 -1
- package/dist/services/internal/AuthService.js.map +1 -1
- package/dist/services/internal/ErrorService.d.ts +2 -2
- package/dist/services/internal/ErrorService.js +4 -4
- package/dist/services/internal/ErrorService.js.map +1 -1
- package/dist/services/internal/LogService.d.ts +2 -2
- package/dist/services/internal/LogService.js.map +1 -1
- package/dist/services/public/FetcherService.d.ts +7 -9
- package/dist/services/public/FetcherService.js +102 -51
- package/dist/services/public/FetcherService.js.map +1 -1
- package/dist/services/public/ListService.js +4 -4
- package/dist/services/public/ListService.js.map +1 -1
- package/dist/services/public/TweetService.d.ts +3 -3
- package/dist/services/public/TweetService.js +35 -35
- package/dist/services/public/TweetService.js.map +1 -1
- package/dist/services/public/UserService.js +37 -37
- package/dist/services/public/UserService.js.map +1 -1
- package/dist/types/RettiwtConfig.d.ts +6 -3
- package/dist/types/args/FetchArgs.d.ts +2 -2
- package/dist/types/auth/AuthCredential.d.ts +2 -2
- package/dist/types/auth/TransactionHeader.d.ts +6 -0
- package/dist/types/auth/TransactionHeader.js +4 -0
- package/dist/types/auth/TransactionHeader.js.map +1 -0
- package/dist/types/data/Notification.d.ts +2 -2
- package/dist/types/data/Tweet.d.ts +2 -2
- package/dist/types/raw/base/Media.d.ts +2 -2
- package/dist/types/raw/base/Notification.d.ts +2 -2
- package/package.json +19 -18
- package/src/cli.ts +20 -14
- package/src/collections/Extractors.ts +21 -21
- package/src/collections/Groups.ts +45 -45
- package/src/collections/Requests.ts +4 -4
- package/src/collections/Tweet.ts +6 -6
- package/src/commands/Tweet.ts +33 -4
- package/src/enums/Api.ts +1 -1
- package/src/enums/Authentication.ts +1 -1
- package/src/enums/Data.ts +1 -1
- package/src/enums/Logging.ts +1 -1
- package/src/enums/Media.ts +1 -1
- package/src/enums/Notification.ts +1 -1
- package/src/enums/Resource.ts +1 -1
- package/src/enums/Tweet.ts +1 -1
- package/src/enums/raw/Analytics.ts +2 -2
- package/src/enums/raw/Media.ts +1 -1
- package/src/enums/raw/Notification.ts +1 -1
- package/src/enums/raw/Tweet.ts +2 -2
- package/src/index.ts +0 -1
- package/src/models/RettiwtConfig.ts +7 -8
- package/src/models/args/FetchArgs.ts +5 -5
- package/src/models/auth/AuthCredential.ts +5 -5
- package/src/models/data/CursoredData.ts +5 -5
- package/src/models/data/Notification.ts +6 -6
- package/src/models/data/Tweet.ts +22 -22
- package/src/models/data/User.ts +10 -10
- package/src/requests/Tweet.ts +4 -4
- package/src/requests/User.ts +3 -3
- package/src/services/internal/AuthService.ts +2 -2
- package/src/services/internal/ErrorService.ts +4 -4
- package/src/services/internal/LogService.ts +2 -2
- package/src/services/public/FetcherService.ts +82 -57
- package/src/services/public/ListService.ts +6 -6
- package/src/services/public/TweetService.ts +39 -39
- package/src/services/public/UserService.ts +40 -40
- package/src/types/RettiwtConfig.ts +7 -4
- package/src/types/args/FetchArgs.ts +2 -2
- package/src/types/auth/AuthCredential.ts +2 -2
- package/src/types/auth/TransactionHeader.ts +8 -0
- package/src/types/data/Notification.ts +2 -2
- package/src/types/data/Tweet.ts +2 -2
- package/src/types/raw/base/Media.ts +2 -2
- package/src/types/raw/base/Notification.ts +2 -2
- package/.tool-versions +0 -1
- package/dist/helper/TidUtils.d.ts +0 -4
- package/dist/helper/TidUtils.js +0 -171
- package/dist/helper/TidUtils.js.map +0 -1
- package/dist/services/internal/TidService.d.ts +0 -43
- package/dist/services/internal/TidService.js +0 -156
- package/dist/services/internal/TidService.js.map +0 -1
- package/dist/types/auth/TidDynamicArgs.d.ts +0 -10
- package/dist/types/auth/TidDynamicArgs.js +0 -3
- package/dist/types/auth/TidDynamicArgs.js.map +0 -1
- package/dist/types/auth/TidHeader.d.ts +0 -8
- package/dist/types/auth/TidHeader.js +0 -3
- package/dist/types/auth/TidHeader.js.map +0 -1
- package/dist/types/auth/TidParams.d.ts +0 -27
- package/dist/types/auth/TidParams.js +0 -3
- package/dist/types/auth/TidParams.js.map +0 -1
- package/dist/types/auth/TidProvider.d.ts +0 -18
- package/dist/types/auth/TidProvider.js +0 -3
- package/dist/types/auth/TidProvider.js.map +0 -1
- package/src/helper/TidUtils.ts +0 -198
- package/src/services/internal/TidService.ts +0 -140
- package/src/types/auth/TidDynamicArgs.ts +0 -10
- package/src/types/auth/TidHeader.ts +0 -12
- package/src/types/auth/TidParams.ts +0 -36
- package/src/types/auth/TidProvider.ts +0 -19
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { NotificationType } from '../../enums/Notification';
|
|
2
|
+
import { RawNotificationType } from '../../enums/raw/Notification';
|
|
3
3
|
import { findKeyByValue } from '../../helper/JsonUtils';
|
|
4
4
|
import { INotification } from '../../types/data/Notification';
|
|
5
5
|
import { INotification as IRawNotification } from '../../types/raw/base/Notification';
|
|
@@ -19,7 +19,7 @@ export class Notification implements INotification {
|
|
|
19
19
|
public message: string;
|
|
20
20
|
public receivedAt: string;
|
|
21
21
|
public target: string[];
|
|
22
|
-
public type?:
|
|
22
|
+
public type?: NotificationType;
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* @param notification - The raw notification details.
|
|
@@ -28,7 +28,7 @@ export class Notification implements INotification {
|
|
|
28
28
|
this._raw = { ...notification };
|
|
29
29
|
|
|
30
30
|
// Getting the original notification type
|
|
31
|
-
const notificationType: string | undefined = findKeyByValue(
|
|
31
|
+
const notificationType: string | undefined = findKeyByValue(RawNotificationType, notification.icon.id);
|
|
32
32
|
|
|
33
33
|
this.from = notification.template?.aggregateUserActionsV1?.fromUsers
|
|
34
34
|
? notification.template.aggregateUserActionsV1.fromUsers.map((item) => item.user.id)
|
|
@@ -40,8 +40,8 @@ export class Notification implements INotification {
|
|
|
40
40
|
? notification.template.aggregateUserActionsV1.targetObjects.map((item) => item.tweet.id)
|
|
41
41
|
: [];
|
|
42
42
|
this.type = notificationType
|
|
43
|
-
?
|
|
44
|
-
:
|
|
43
|
+
? NotificationType[notificationType as keyof typeof NotificationType]
|
|
44
|
+
: NotificationType.UNDEFINED;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/** The raw notification details. */
|
package/src/models/data/Tweet.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { LogActions } from '../../enums/Logging';
|
|
2
|
+
import { MediaType } from '../../enums/Media';
|
|
3
|
+
import { RawMediaType } from '../../enums/raw/Media';
|
|
4
4
|
import { findByFilter } from '../../helper/JsonUtils';
|
|
5
5
|
|
|
6
6
|
import { LogService } from '../../services/internal/LogService';
|
|
@@ -52,7 +52,7 @@ export class Tweet implements ITweet {
|
|
|
52
52
|
this.tweetBy = new User(tweet.core.user_results.result);
|
|
53
53
|
this.entities = new TweetEntities(tweet.legacy.entities);
|
|
54
54
|
this.media = tweet.legacy.extended_entities?.media?.map((media) => new TweetMedia(media));
|
|
55
|
-
this.quoted = this.
|
|
55
|
+
this.quoted = this._getQuotedTweet(tweet);
|
|
56
56
|
this.fullText = tweet.note_tweet ? tweet.note_tweet.note_tweet_results.result.text : tweet.legacy.full_text;
|
|
57
57
|
this.replyTo = tweet.legacy.in_reply_to_status_id_str;
|
|
58
58
|
this.lang = tweet.legacy.lang;
|
|
@@ -62,7 +62,7 @@ export class Tweet implements ITweet {
|
|
|
62
62
|
this.likeCount = tweet.legacy.favorite_count;
|
|
63
63
|
this.viewCount = tweet.views.count ? parseInt(tweet.views.count) : 0;
|
|
64
64
|
this.bookmarkCount = tweet.legacy.bookmark_count;
|
|
65
|
-
this.retweetedTweet = this.
|
|
65
|
+
this.retweetedTweet = this._getRetweetedTweet(tweet);
|
|
66
66
|
this.url = `https://x.com/${this.tweetBy.userName}/status/${this.id}`;
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -78,7 +78,7 @@ export class Tweet implements ITweet {
|
|
|
78
78
|
*
|
|
79
79
|
* @returns - The deserialized original quoted tweet.
|
|
80
80
|
*/
|
|
81
|
-
private
|
|
81
|
+
private _getQuotedTweet(tweet: IRawTweet): Tweet | undefined {
|
|
82
82
|
// If tweet with limited visibility
|
|
83
83
|
if (
|
|
84
84
|
tweet.quoted_status_result &&
|
|
@@ -104,7 +104,7 @@ export class Tweet implements ITweet {
|
|
|
104
104
|
*
|
|
105
105
|
* @returns - The deserialized original retweeted tweet.
|
|
106
106
|
*/
|
|
107
|
-
private
|
|
107
|
+
private _getRetweetedTweet(tweet: IRawTweet): Tweet | undefined {
|
|
108
108
|
// If retweet with limited visibility
|
|
109
109
|
if (
|
|
110
110
|
tweet.legacy?.retweeted_status_result &&
|
|
@@ -141,13 +141,13 @@ export class Tweet implements ITweet {
|
|
|
141
141
|
for (const item of extract) {
|
|
142
142
|
if (item.legacy) {
|
|
143
143
|
// Logging
|
|
144
|
-
LogService.log(
|
|
144
|
+
LogService.log(LogActions.DESERIALIZE, { id: item.rest_id });
|
|
145
145
|
|
|
146
146
|
tweets.push(new Tweet(item));
|
|
147
147
|
} else {
|
|
148
148
|
// Logging
|
|
149
|
-
LogService.log(
|
|
150
|
-
action:
|
|
149
|
+
LogService.log(LogActions.WARNING, {
|
|
150
|
+
action: LogActions.DESERIALIZE,
|
|
151
151
|
message: `Tweet not found, skipping`,
|
|
152
152
|
});
|
|
153
153
|
}
|
|
@@ -179,13 +179,13 @@ export class Tweet implements ITweet {
|
|
|
179
179
|
for (const item of extract) {
|
|
180
180
|
if (item.legacy) {
|
|
181
181
|
// Logging
|
|
182
|
-
LogService.log(
|
|
182
|
+
LogService.log(LogActions.DESERIALIZE, { id: item.rest_id });
|
|
183
183
|
|
|
184
184
|
tweets.push(new Tweet(item));
|
|
185
185
|
} else {
|
|
186
186
|
// Logging
|
|
187
|
-
LogService.log(
|
|
188
|
-
action:
|
|
187
|
+
LogService.log(LogActions.WARNING, {
|
|
188
|
+
action: LogActions.DESERIALIZE,
|
|
189
189
|
message: `Tweet not found, skipping`,
|
|
190
190
|
});
|
|
191
191
|
}
|
|
@@ -221,15 +221,15 @@ export class Tweet implements ITweet {
|
|
|
221
221
|
// If normal tweet
|
|
222
222
|
else if ((item.tweet_results?.result as IRawTweet)?.legacy) {
|
|
223
223
|
// Logging
|
|
224
|
-
LogService.log(
|
|
224
|
+
LogService.log(LogActions.DESERIALIZE, { id: (item.tweet_results.result as IRawTweet).rest_id });
|
|
225
225
|
|
|
226
226
|
tweets.push(new Tweet(item.tweet_results.result as IRawTweet));
|
|
227
227
|
}
|
|
228
228
|
// If invalid/unrecognized tweet
|
|
229
229
|
else {
|
|
230
230
|
// Logging
|
|
231
|
-
LogService.log(
|
|
232
|
-
action:
|
|
231
|
+
LogService.log(LogActions.WARNING, {
|
|
232
|
+
action: LogActions.DESERIALIZE,
|
|
233
233
|
message: `Tweet not found, skipping`,
|
|
234
234
|
});
|
|
235
235
|
}
|
|
@@ -328,7 +328,7 @@ export class TweetMedia {
|
|
|
328
328
|
public thumbnailUrl?: string;
|
|
329
329
|
|
|
330
330
|
/** The type of media. */
|
|
331
|
-
public type:
|
|
331
|
+
public type: MediaType;
|
|
332
332
|
|
|
333
333
|
/** The direct URL to the media. */
|
|
334
334
|
public url = '';
|
|
@@ -338,18 +338,18 @@ export class TweetMedia {
|
|
|
338
338
|
*/
|
|
339
339
|
public constructor(media: IRawExtendedMedia) {
|
|
340
340
|
// If the media is a photo
|
|
341
|
-
if (media.type ==
|
|
342
|
-
this.type =
|
|
341
|
+
if (media.type == RawMediaType.PHOTO) {
|
|
342
|
+
this.type = MediaType.PHOTO;
|
|
343
343
|
this.url = media.media_url_https;
|
|
344
344
|
}
|
|
345
345
|
// If the media is a gif
|
|
346
|
-
else if (media.type ==
|
|
347
|
-
this.type =
|
|
346
|
+
else if (media.type == RawMediaType.GIF) {
|
|
347
|
+
this.type = MediaType.GIF;
|
|
348
348
|
this.url = media.video_info?.variants[0].url as string;
|
|
349
349
|
}
|
|
350
350
|
// If the media is a video
|
|
351
351
|
else {
|
|
352
|
-
this.type =
|
|
352
|
+
this.type = MediaType.VIDEO;
|
|
353
353
|
this.thumbnailUrl = media.media_url_https;
|
|
354
354
|
|
|
355
355
|
/** The highest bitrate of all variants. */
|
package/src/models/data/User.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LogActions } from '../../enums/Logging';
|
|
2
2
|
import { findByFilter } from '../../helper/JsonUtils';
|
|
3
3
|
import { LogService } from '../../services/internal/LogService';
|
|
4
4
|
import { IUser } from '../../types/data/User';
|
|
@@ -73,13 +73,13 @@ export class User implements IUser {
|
|
|
73
73
|
for (const item of extract) {
|
|
74
74
|
if (item.legacy && item.legacy.created_at) {
|
|
75
75
|
// Logging
|
|
76
|
-
LogService.log(
|
|
76
|
+
LogService.log(LogActions.DESERIALIZE, { id: item.rest_id });
|
|
77
77
|
|
|
78
78
|
users.push(new User(item));
|
|
79
79
|
} else {
|
|
80
80
|
// Logging
|
|
81
|
-
LogService.log(
|
|
82
|
-
action:
|
|
81
|
+
LogService.log(LogActions.WARNING, {
|
|
82
|
+
action: LogActions.DESERIALIZE,
|
|
83
83
|
message: `User not found, skipping`,
|
|
84
84
|
});
|
|
85
85
|
}
|
|
@@ -110,13 +110,13 @@ export class User implements IUser {
|
|
|
110
110
|
for (const item of extract) {
|
|
111
111
|
if (item.legacy && item.legacy.created_at) {
|
|
112
112
|
// Logging
|
|
113
|
-
LogService.log(
|
|
113
|
+
LogService.log(LogActions.DESERIALIZE, { id: item.rest_id });
|
|
114
114
|
|
|
115
115
|
users.push(new User(item));
|
|
116
116
|
} else {
|
|
117
117
|
// Logging
|
|
118
|
-
LogService.log(
|
|
119
|
-
action:
|
|
118
|
+
LogService.log(LogActions.WARNING, {
|
|
119
|
+
action: LogActions.DESERIALIZE,
|
|
120
120
|
message: `User not found, skipping`,
|
|
121
121
|
});
|
|
122
122
|
}
|
|
@@ -142,13 +142,13 @@ export class User implements IUser {
|
|
|
142
142
|
for (const item of extract) {
|
|
143
143
|
if (item.user_results?.result?.legacy) {
|
|
144
144
|
// Logging
|
|
145
|
-
LogService.log(
|
|
145
|
+
LogService.log(LogActions.DESERIALIZE, { id: item.user_results.result.rest_id });
|
|
146
146
|
|
|
147
147
|
users.push(new User(item.user_results.result));
|
|
148
148
|
} else {
|
|
149
149
|
// Logging
|
|
150
|
-
LogService.log(
|
|
151
|
-
action:
|
|
150
|
+
LogService.log(LogActions.WARNING, {
|
|
151
|
+
action: LogActions.DESERIALIZE,
|
|
152
152
|
message: `User not found, skipping`,
|
|
153
153
|
});
|
|
154
154
|
}
|
package/src/requests/Tweet.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AxiosRequestConfig } from 'axios';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { RawTweetRepliesSortType, RawTweetSearchResultType } from '../enums/raw/Tweet';
|
|
4
4
|
import { TweetFilter } from '../models/args/FetchArgs';
|
|
5
5
|
import { NewTweet } from '../models/args/PostArgs';
|
|
6
6
|
import { MediaVariable, ReplyVariable } from '../models/params/Variables';
|
|
@@ -266,7 +266,7 @@ export class TweetRequests {
|
|
|
266
266
|
* @param id - The id of the tweet whose replies are to be fetched.
|
|
267
267
|
* @param cursor - The cursor to the batch of replies to fetch.
|
|
268
268
|
*/
|
|
269
|
-
public static replies(id: string, cursor?: string, sortBy?:
|
|
269
|
+
public static replies(id: string, cursor?: string, sortBy?: RawTweetRepliesSortType): AxiosRequestConfig {
|
|
270
270
|
return {
|
|
271
271
|
method: 'get',
|
|
272
272
|
url: 'https://x.com/i/api/graphql/_8aYOgEDz35BrBcBal1-_w/TweetDetail',
|
|
@@ -277,7 +277,7 @@ export class TweetRequests {
|
|
|
277
277
|
cursor: cursor,
|
|
278
278
|
referrer: 'tweet',
|
|
279
279
|
with_rux_injections: false,
|
|
280
|
-
rankingMode: sortBy ??
|
|
280
|
+
rankingMode: sortBy ?? RawTweetRepliesSortType.RELEVACE,
|
|
281
281
|
includePromotedContent: true,
|
|
282
282
|
withCommunity: true,
|
|
283
283
|
withQuickPromoteEligibilityTweetFields: true,
|
|
@@ -451,7 +451,7 @@ export class TweetRequests {
|
|
|
451
451
|
count: count,
|
|
452
452
|
cursor: cursor,
|
|
453
453
|
querySource: 'typed_query',
|
|
454
|
-
product: parsedFilter.top ?
|
|
454
|
+
product: parsedFilter.top ? RawTweetSearchResultType.TOP : RawTweetSearchResultType.LATEST,
|
|
455
455
|
withAuxiliaryUserLabels: false,
|
|
456
456
|
withArticleRichContentState: false,
|
|
457
457
|
withArticlePlainText: false,
|
package/src/requests/User.ts
CHANGED
|
@@ -2,7 +2,7 @@ import qs from 'querystring';
|
|
|
2
2
|
|
|
3
3
|
import { AxiosRequestConfig } from 'axios';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { RawAnalyticsGranularity, RawAnalyticsMetric } from '../enums/raw/Analytics';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Collection of requests related to users.
|
|
@@ -77,8 +77,8 @@ export class UserRequests {
|
|
|
77
77
|
public static analytics(
|
|
78
78
|
fromTime: Date,
|
|
79
79
|
toTime: Date,
|
|
80
|
-
granularity:
|
|
81
|
-
requestedMetrics:
|
|
80
|
+
granularity: RawAnalyticsGranularity,
|
|
81
|
+
requestedMetrics: RawAnalyticsMetric[],
|
|
82
82
|
): AxiosRequestConfig {
|
|
83
83
|
return {
|
|
84
84
|
method: 'get',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { ApiErrors } from '../../enums/Api';
|
|
4
4
|
import { AuthCredential } from '../../models/auth/AuthCredential';
|
|
5
5
|
import { RettiwtConfig } from '../../models/RettiwtConfig';
|
|
6
6
|
|
|
@@ -67,7 +67,7 @@ export class AuthService {
|
|
|
67
67
|
}
|
|
68
68
|
// If user id was not found
|
|
69
69
|
else {
|
|
70
|
-
throw new Error(
|
|
70
|
+
throw new Error(ApiErrors.BAD_AUTHENTICATION);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -15,14 +15,14 @@ export class ErrorService implements IErrorHandler {
|
|
|
15
15
|
*
|
|
16
16
|
* @param error - The error response received from Twitter.
|
|
17
17
|
*/
|
|
18
|
-
private
|
|
18
|
+
private _handleAxiosError(error: AxiosError<IRawErrorData | IRawErrorDetails>): void {
|
|
19
19
|
throw new TwitterError(error);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Handle unknown error.
|
|
24
24
|
*/
|
|
25
|
-
private
|
|
25
|
+
private _handleUnknownError(): void {
|
|
26
26
|
throw new Error('Unknown error');
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -33,9 +33,9 @@ export class ErrorService implements IErrorHandler {
|
|
|
33
33
|
*/
|
|
34
34
|
public handle(error: unknown): void {
|
|
35
35
|
if (isAxiosError(error)) {
|
|
36
|
-
this.
|
|
36
|
+
this._handleAxiosError(error as AxiosError<IRawErrorData | IRawErrorDetails>);
|
|
37
37
|
} else {
|
|
38
|
-
this.
|
|
38
|
+
this._handleUnknownError();
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LogActions } from '../../enums/Logging';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Handles logging of data for debug purpose.
|
|
@@ -16,7 +16,7 @@ export class LogService {
|
|
|
16
16
|
*
|
|
17
17
|
* @param data - The data to be logged.
|
|
18
18
|
*/
|
|
19
|
-
public static log(action:
|
|
19
|
+
public static log(action: LogActions, data: NonNullable<unknown>): void {
|
|
20
20
|
// Proceed to log only if logging is enabled
|
|
21
21
|
if (this.enabled) {
|
|
22
22
|
// Preparing the log message
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable import/no-unresolved */
|
|
2
|
+
import { ClientTransaction, handleXMigration } from '@lami/x-client-transaction-id';
|
|
3
|
+
import axios, { isAxiosError } from 'axios';
|
|
2
4
|
import { Cookie } from 'cookiejar';
|
|
3
5
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { AllowGuestAuthenticationGroup, FetchResourcesGroup, PostResourcesGroup } from '../../collections/Groups';
|
|
7
|
+
import { Requests } from '../../collections/Requests';
|
|
8
|
+
import { ApiErrors } from '../../enums/Api';
|
|
9
|
+
import { LogActions } from '../../enums/Logging';
|
|
10
|
+
import { ResourceType } from '../../enums/Resource';
|
|
9
11
|
import { FetchArgs } from '../../models/args/FetchArgs';
|
|
10
12
|
import { PostArgs } from '../../models/args/PostArgs';
|
|
11
13
|
import { AuthCredential } from '../../models/auth/AuthCredential';
|
|
12
14
|
import { RettiwtConfig } from '../../models/RettiwtConfig';
|
|
13
15
|
import { IFetchArgs } from '../../types/args/FetchArgs';
|
|
14
16
|
import { IPostArgs } from '../../types/args/PostArgs';
|
|
15
|
-
import {
|
|
16
|
-
import { ITidProvider } from '../../types/auth/TidProvider';
|
|
17
|
+
import { ITransactionHeader } from '../../types/auth/TransactionHeader';
|
|
17
18
|
import { IErrorHandler } from '../../types/ErrorHandler';
|
|
18
19
|
|
|
19
20
|
import { AuthService } from '../internal/AuthService';
|
|
20
21
|
import { ErrorService } from '../internal/ErrorService';
|
|
21
22
|
import { LogService } from '../internal/LogService';
|
|
22
|
-
import { TidService } from '../internal/TidService';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* The base service that handles all HTTP requests.
|
|
@@ -36,9 +36,6 @@ export class FetcherService {
|
|
|
36
36
|
/** The service used to handle HTTP and API errors */
|
|
37
37
|
private readonly _errorHandler: IErrorHandler;
|
|
38
38
|
|
|
39
|
-
/** Service responsible for generating the `x-client-transaction-id` header. */
|
|
40
|
-
private readonly _tidProvider: ITidProvider;
|
|
41
|
-
|
|
42
39
|
/** The max wait time for a response. */
|
|
43
40
|
private readonly _timeout: number;
|
|
44
41
|
|
|
@@ -53,7 +50,6 @@ export class FetcherService {
|
|
|
53
50
|
this.config = config;
|
|
54
51
|
this._delay = config.delay;
|
|
55
52
|
this._errorHandler = config.errorHandler ?? new ErrorService();
|
|
56
|
-
this._tidProvider = config.tidProvider ?? new TidService(config);
|
|
57
53
|
this._timeout = config.timeout ?? 0;
|
|
58
54
|
this._auth = new AuthService(config);
|
|
59
55
|
}
|
|
@@ -65,13 +61,13 @@ export class FetcherService {
|
|
|
65
61
|
*
|
|
66
62
|
* @throws An error if not authorized to access the requested resource.
|
|
67
63
|
*/
|
|
68
|
-
private
|
|
64
|
+
private _checkAuthorization(resource: ResourceType): void {
|
|
69
65
|
// Logging
|
|
70
|
-
LogService.log(
|
|
66
|
+
LogService.log(LogActions.AUTHORIZATION, { authenticated: this.config.userId != undefined });
|
|
71
67
|
|
|
72
68
|
// Checking authorization status
|
|
73
|
-
if (!
|
|
74
|
-
throw new Error(
|
|
69
|
+
if (!AllowGuestAuthenticationGroup.includes(resource) && this.config.userId == undefined) {
|
|
70
|
+
throw new Error(ApiErrors.RESOURCE_NOT_ALLOWED);
|
|
75
71
|
}
|
|
76
72
|
}
|
|
77
73
|
|
|
@@ -80,10 +76,10 @@ export class FetcherService {
|
|
|
80
76
|
*
|
|
81
77
|
* @returns The generated AuthCredential
|
|
82
78
|
*/
|
|
83
|
-
private async
|
|
79
|
+
private async _getCredential(): Promise<AuthCredential> {
|
|
84
80
|
if (this.config.apiKey) {
|
|
85
81
|
// Logging
|
|
86
|
-
LogService.log(
|
|
82
|
+
LogService.log(LogActions.GET, { target: 'USER_CREDENTIAL' });
|
|
87
83
|
|
|
88
84
|
return new AuthCredential(
|
|
89
85
|
AuthService.decodeCookie(this.config.apiKey)
|
|
@@ -92,7 +88,7 @@ export class FetcherService {
|
|
|
92
88
|
);
|
|
93
89
|
} else {
|
|
94
90
|
// Logging
|
|
95
|
-
LogService.log(
|
|
91
|
+
LogService.log(LogActions.GET, { target: 'NEW_GUEST_CREDENTIAL' });
|
|
96
92
|
|
|
97
93
|
return this._auth.guest();
|
|
98
94
|
}
|
|
@@ -106,22 +102,24 @@ export class FetcherService {
|
|
|
106
102
|
*
|
|
107
103
|
* @returns The header containing the transaction ID.
|
|
108
104
|
*/
|
|
109
|
-
private async
|
|
105
|
+
private async _getTransactionHeader(method: string, url: string): Promise<ITransactionHeader> {
|
|
106
|
+
// Get the X homepage HTML document (using utility function)
|
|
107
|
+
const document = await handleXMigration();
|
|
108
|
+
|
|
109
|
+
// Create and initialize ClientTransaction instance
|
|
110
|
+
const transaction = await ClientTransaction.create(document);
|
|
111
|
+
|
|
110
112
|
// Getting the URL path excluding all params
|
|
111
113
|
const path = new URL(url).pathname.split('?')[0].trim();
|
|
112
114
|
|
|
113
115
|
// Generating the transaction ID
|
|
114
|
-
const tid = await
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
};
|
|
122
|
-
} else {
|
|
123
|
-
return undefined;
|
|
124
|
-
}
|
|
116
|
+
const tid = await transaction.generateTransactionId(method.toUpperCase(), path);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
120
|
+
'x-client-transaction-id': tid,
|
|
121
|
+
/* eslint-enable @typescript-eslint/naming-convention */
|
|
122
|
+
};
|
|
125
123
|
}
|
|
126
124
|
|
|
127
125
|
/**
|
|
@@ -132,15 +130,15 @@ export class FetcherService {
|
|
|
132
130
|
*
|
|
133
131
|
* @returns The validated args.
|
|
134
132
|
*/
|
|
135
|
-
private
|
|
136
|
-
if (
|
|
133
|
+
private _validateArgs(resource: ResourceType, args: IFetchArgs | IPostArgs): FetchArgs | PostArgs | undefined {
|
|
134
|
+
if (FetchResourcesGroup.includes(resource)) {
|
|
137
135
|
// Logging
|
|
138
|
-
LogService.log(
|
|
136
|
+
LogService.log(LogActions.VALIDATE, { target: 'FETCH_ARGS' });
|
|
139
137
|
|
|
140
138
|
return new FetchArgs(args);
|
|
141
|
-
} else if (
|
|
139
|
+
} else if (PostResourcesGroup.includes(resource)) {
|
|
142
140
|
// Logging
|
|
143
|
-
LogService.log(
|
|
141
|
+
LogService.log(LogActions.VALIDATE, { target: 'POST_ARGS' });
|
|
144
142
|
|
|
145
143
|
return new PostArgs(args);
|
|
146
144
|
}
|
|
@@ -149,7 +147,7 @@ export class FetcherService {
|
|
|
149
147
|
/**
|
|
150
148
|
* Introduces a delay using the configured delay/delay function.
|
|
151
149
|
*/
|
|
152
|
-
private async
|
|
150
|
+
private async _wait(): Promise<void> {
|
|
153
151
|
// If no delay is set, skip
|
|
154
152
|
if (this._delay == undefined) {
|
|
155
153
|
return;
|
|
@@ -198,44 +196,71 @@ export class FetcherService {
|
|
|
198
196
|
* });
|
|
199
197
|
* ```
|
|
200
198
|
*/
|
|
201
|
-
public async request<T = unknown>(resource:
|
|
199
|
+
public async request<T = unknown>(resource: ResourceType, args: IFetchArgs | IPostArgs): Promise<T> {
|
|
200
|
+
/** The current retry number. */
|
|
201
|
+
let retry = 0;
|
|
202
|
+
|
|
203
|
+
/** The error, if any. */
|
|
204
|
+
let error: unknown = undefined;
|
|
205
|
+
|
|
202
206
|
// Logging
|
|
203
|
-
LogService.log(
|
|
207
|
+
LogService.log(LogActions.REQUEST, { resource: resource, args: args });
|
|
204
208
|
|
|
205
209
|
// Checking authorization for the requested resource
|
|
206
|
-
this.
|
|
210
|
+
this._checkAuthorization(resource);
|
|
207
211
|
|
|
208
212
|
// Validating args
|
|
209
|
-
args = this.
|
|
213
|
+
args = this._validateArgs(resource, args)!;
|
|
210
214
|
|
|
211
215
|
// Getting credentials from key
|
|
212
|
-
const cred: AuthCredential = await this.
|
|
216
|
+
const cred: AuthCredential = await this._getCredential();
|
|
213
217
|
|
|
214
218
|
// Getting request configuration
|
|
215
|
-
const config =
|
|
219
|
+
const config = Requests[resource](args);
|
|
216
220
|
|
|
217
221
|
// Setting additional request parameters
|
|
218
222
|
config.headers = {
|
|
219
223
|
...config.headers,
|
|
220
224
|
...cred.toHeader(),
|
|
221
|
-
...(await this.getTransactionHeader(config.method ?? '', config.url ?? '')),
|
|
222
225
|
...this.config.headers,
|
|
223
226
|
};
|
|
224
227
|
config.httpAgent = this.config.httpsAgent;
|
|
225
228
|
config.httpsAgent = this.config.httpsAgent;
|
|
226
229
|
config.timeout = this._timeout;
|
|
227
230
|
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
231
|
+
// Using retries for error 404
|
|
232
|
+
do {
|
|
233
|
+
// Sending the request
|
|
234
|
+
try {
|
|
235
|
+
// Getting and appending transaction information
|
|
236
|
+
config.headers = {
|
|
237
|
+
...config.headers,
|
|
238
|
+
...(await this._getTransactionHeader(config.method ?? '', config.url ?? '')),
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// Introducing a delay
|
|
242
|
+
await this._wait();
|
|
243
|
+
|
|
244
|
+
// Returning the reponse body
|
|
245
|
+
return (await axios<T>(config)).data;
|
|
246
|
+
} catch (err) {
|
|
247
|
+
// If it's an error 404, retry
|
|
248
|
+
if (isAxiosError(err) && err.status === 404) {
|
|
249
|
+
error = err;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
// Else, delegate error handling
|
|
253
|
+
else {
|
|
254
|
+
this._errorHandler.handle(err);
|
|
255
|
+
throw err;
|
|
256
|
+
}
|
|
257
|
+
} finally {
|
|
258
|
+
// Incrementing the number of retries done
|
|
259
|
+
retry++;
|
|
260
|
+
}
|
|
261
|
+
} while (retry < this.config.maxRetries);
|
|
262
|
+
|
|
263
|
+
/** If request not successful even after retries, throw the error */
|
|
264
|
+
throw error;
|
|
240
265
|
}
|
|
241
266
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Extractors } from '../../collections/Extractors';
|
|
2
|
+
import { ResourceType } from '../../enums/Resource';
|
|
3
3
|
import { CursoredData } from '../../models/data/CursoredData';
|
|
4
4
|
import { Tweet } from '../../models/data/Tweet';
|
|
5
5
|
import { User } from '../../models/data/User';
|
|
@@ -49,7 +49,7 @@ export class ListService extends FetcherService {
|
|
|
49
49
|
* @remarks Due a bug in Twitter API, the count is ignored when no cursor is provided and defaults to 100.
|
|
50
50
|
*/
|
|
51
51
|
public async members(id: string, count?: number, cursor?: string): Promise<CursoredData<User>> {
|
|
52
|
-
const resource:
|
|
52
|
+
const resource: ResourceType = ResourceType.LIST_MEMBERS;
|
|
53
53
|
|
|
54
54
|
// Fetching the raw list of members
|
|
55
55
|
const response = await this.request<IListMembersResponse>(resource, {
|
|
@@ -59,7 +59,7 @@ export class ListService extends FetcherService {
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
// Deserializing response
|
|
62
|
-
const data =
|
|
62
|
+
const data = Extractors[resource](response);
|
|
63
63
|
|
|
64
64
|
return data;
|
|
65
65
|
}
|
|
@@ -94,7 +94,7 @@ export class ListService extends FetcherService {
|
|
|
94
94
|
* @remarks Due a bug in Twitter API, the count is ignored when no cursor is provided and defaults to 100.
|
|
95
95
|
*/
|
|
96
96
|
public async tweets(id: string, count?: number, cursor?: string): Promise<CursoredData<Tweet>> {
|
|
97
|
-
const resource =
|
|
97
|
+
const resource = ResourceType.LIST_TWEETS;
|
|
98
98
|
|
|
99
99
|
// Fetching raw list tweets
|
|
100
100
|
const response = await this.request<IListTweetsResponse>(resource, {
|
|
@@ -104,7 +104,7 @@ export class ListService extends FetcherService {
|
|
|
104
104
|
});
|
|
105
105
|
|
|
106
106
|
// Deserializing response
|
|
107
|
-
const data =
|
|
107
|
+
const data = Extractors[resource](response);
|
|
108
108
|
|
|
109
109
|
// Sorting the tweets by date, from recent to oldest
|
|
110
110
|
data.list.sort((a, b) => new Date(b.createdAt).valueOf() - new Date(a.createdAt).valueOf());
|