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.
Files changed (178) hide show
  1. package/.eslintrc.js +13 -8
  2. package/README.md +8 -1
  3. package/dist/cli.js +17 -14
  4. package/dist/cli.js.map +1 -1
  5. package/dist/collections/Extractors.d.ts +1 -1
  6. package/dist/collections/Extractors.js +21 -21
  7. package/dist/collections/Extractors.js.map +1 -1
  8. package/dist/collections/Groups.d.ts +4 -4
  9. package/dist/collections/Groups.js +45 -45
  10. package/dist/collections/Groups.js.map +1 -1
  11. package/dist/collections/Requests.d.ts +3 -3
  12. package/dist/collections/Requests.js +3 -3
  13. package/dist/collections/Requests.js.map +1 -1
  14. package/dist/collections/Tweet.d.ts +4 -4
  15. package/dist/collections/Tweet.js +5 -5
  16. package/dist/collections/Tweet.js.map +1 -1
  17. package/dist/commands/Tweet.js +32 -4
  18. package/dist/commands/Tweet.js.map +1 -1
  19. package/dist/enums/Api.d.ts +1 -1
  20. package/dist/enums/Api.js +7 -7
  21. package/dist/enums/Api.js.map +1 -1
  22. package/dist/enums/Authentication.d.ts +1 -1
  23. package/dist/enums/Authentication.js +7 -7
  24. package/dist/enums/Authentication.js.map +1 -1
  25. package/dist/enums/Data.d.ts +1 -1
  26. package/dist/enums/Data.js +7 -7
  27. package/dist/enums/Data.js.map +1 -1
  28. package/dist/enums/Logging.d.ts +1 -1
  29. package/dist/enums/Logging.js +11 -11
  30. package/dist/enums/Logging.js.map +1 -1
  31. package/dist/enums/Media.d.ts +1 -1
  32. package/dist/enums/Media.js +7 -7
  33. package/dist/enums/Media.js.map +1 -1
  34. package/dist/enums/Notification.d.ts +1 -1
  35. package/dist/enums/Notification.js +9 -9
  36. package/dist/enums/Notification.js.map +1 -1
  37. package/dist/enums/Resource.d.ts +1 -1
  38. package/dist/enums/Resource.js +42 -42
  39. package/dist/enums/Resource.js.map +1 -1
  40. package/dist/enums/Tweet.d.ts +1 -1
  41. package/dist/enums/Tweet.js +7 -7
  42. package/dist/enums/Tweet.js.map +1 -1
  43. package/dist/enums/raw/Analytics.d.ts +2 -2
  44. package/dist/enums/raw/Analytics.js +21 -21
  45. package/dist/enums/raw/Analytics.js.map +1 -1
  46. package/dist/enums/raw/Media.d.ts +1 -1
  47. package/dist/enums/raw/Media.js +7 -7
  48. package/dist/enums/raw/Media.js.map +1 -1
  49. package/dist/enums/raw/Notification.d.ts +1 -1
  50. package/dist/enums/raw/Notification.js +8 -8
  51. package/dist/enums/raw/Notification.js.map +1 -1
  52. package/dist/enums/raw/Tweet.d.ts +2 -2
  53. package/dist/enums/raw/Tweet.js +12 -12
  54. package/dist/enums/raw/Tweet.js.map +1 -1
  55. package/dist/index.d.ts +0 -1
  56. package/dist/index.js +0 -1
  57. package/dist/index.js.map +1 -1
  58. package/dist/models/RettiwtConfig.d.ts +3 -4
  59. package/dist/models/RettiwtConfig.js +7 -7
  60. package/dist/models/RettiwtConfig.js.map +1 -1
  61. package/dist/models/args/FetchArgs.d.ts +3 -3
  62. package/dist/models/args/FetchArgs.js +3 -3
  63. package/dist/models/args/FetchArgs.js.map +1 -1
  64. package/dist/models/auth/AuthCredential.d.ts +2 -2
  65. package/dist/models/auth/AuthCredential.js +3 -3
  66. package/dist/models/auth/AuthCredential.js.map +1 -1
  67. package/dist/models/data/CursoredData.d.ts +2 -2
  68. package/dist/models/data/CursoredData.js +3 -3
  69. package/dist/models/data/CursoredData.js.map +1 -1
  70. package/dist/models/data/Notification.d.ts +2 -2
  71. package/dist/models/data/Notification.js +3 -3
  72. package/dist/models/data/Notification.js.map +1 -1
  73. package/dist/models/data/Tweet.d.ts +4 -4
  74. package/dist/models/data/Tweet.js +18 -18
  75. package/dist/models/data/Tweet.js.map +1 -1
  76. package/dist/models/data/User.js +9 -9
  77. package/dist/models/data/User.js.map +1 -1
  78. package/dist/requests/Tweet.d.ts +2 -2
  79. package/dist/requests/Tweet.js +2 -2
  80. package/dist/requests/Tweet.js.map +1 -1
  81. package/dist/requests/User.d.ts +2 -2
  82. package/dist/requests/User.js.map +1 -1
  83. package/dist/services/internal/AuthService.js +1 -1
  84. package/dist/services/internal/AuthService.js.map +1 -1
  85. package/dist/services/internal/ErrorService.d.ts +2 -2
  86. package/dist/services/internal/ErrorService.js +4 -4
  87. package/dist/services/internal/ErrorService.js.map +1 -1
  88. package/dist/services/internal/LogService.d.ts +2 -2
  89. package/dist/services/internal/LogService.js.map +1 -1
  90. package/dist/services/public/FetcherService.d.ts +7 -9
  91. package/dist/services/public/FetcherService.js +102 -51
  92. package/dist/services/public/FetcherService.js.map +1 -1
  93. package/dist/services/public/ListService.js +4 -4
  94. package/dist/services/public/ListService.js.map +1 -1
  95. package/dist/services/public/TweetService.d.ts +3 -3
  96. package/dist/services/public/TweetService.js +35 -35
  97. package/dist/services/public/TweetService.js.map +1 -1
  98. package/dist/services/public/UserService.js +37 -37
  99. package/dist/services/public/UserService.js.map +1 -1
  100. package/dist/types/RettiwtConfig.d.ts +6 -3
  101. package/dist/types/args/FetchArgs.d.ts +2 -2
  102. package/dist/types/auth/AuthCredential.d.ts +2 -2
  103. package/dist/types/auth/TransactionHeader.d.ts +6 -0
  104. package/dist/types/auth/TransactionHeader.js +4 -0
  105. package/dist/types/auth/TransactionHeader.js.map +1 -0
  106. package/dist/types/data/Notification.d.ts +2 -2
  107. package/dist/types/data/Tweet.d.ts +2 -2
  108. package/dist/types/raw/base/Media.d.ts +2 -2
  109. package/dist/types/raw/base/Notification.d.ts +2 -2
  110. package/package.json +19 -18
  111. package/src/cli.ts +20 -14
  112. package/src/collections/Extractors.ts +21 -21
  113. package/src/collections/Groups.ts +45 -45
  114. package/src/collections/Requests.ts +4 -4
  115. package/src/collections/Tweet.ts +6 -6
  116. package/src/commands/Tweet.ts +33 -4
  117. package/src/enums/Api.ts +1 -1
  118. package/src/enums/Authentication.ts +1 -1
  119. package/src/enums/Data.ts +1 -1
  120. package/src/enums/Logging.ts +1 -1
  121. package/src/enums/Media.ts +1 -1
  122. package/src/enums/Notification.ts +1 -1
  123. package/src/enums/Resource.ts +1 -1
  124. package/src/enums/Tweet.ts +1 -1
  125. package/src/enums/raw/Analytics.ts +2 -2
  126. package/src/enums/raw/Media.ts +1 -1
  127. package/src/enums/raw/Notification.ts +1 -1
  128. package/src/enums/raw/Tweet.ts +2 -2
  129. package/src/index.ts +0 -1
  130. package/src/models/RettiwtConfig.ts +7 -8
  131. package/src/models/args/FetchArgs.ts +5 -5
  132. package/src/models/auth/AuthCredential.ts +5 -5
  133. package/src/models/data/CursoredData.ts +5 -5
  134. package/src/models/data/Notification.ts +6 -6
  135. package/src/models/data/Tweet.ts +22 -22
  136. package/src/models/data/User.ts +10 -10
  137. package/src/requests/Tweet.ts +4 -4
  138. package/src/requests/User.ts +3 -3
  139. package/src/services/internal/AuthService.ts +2 -2
  140. package/src/services/internal/ErrorService.ts +4 -4
  141. package/src/services/internal/LogService.ts +2 -2
  142. package/src/services/public/FetcherService.ts +82 -57
  143. package/src/services/public/ListService.ts +6 -6
  144. package/src/services/public/TweetService.ts +39 -39
  145. package/src/services/public/UserService.ts +40 -40
  146. package/src/types/RettiwtConfig.ts +7 -4
  147. package/src/types/args/FetchArgs.ts +2 -2
  148. package/src/types/auth/AuthCredential.ts +2 -2
  149. package/src/types/auth/TransactionHeader.ts +8 -0
  150. package/src/types/data/Notification.ts +2 -2
  151. package/src/types/data/Tweet.ts +2 -2
  152. package/src/types/raw/base/Media.ts +2 -2
  153. package/src/types/raw/base/Notification.ts +2 -2
  154. package/.tool-versions +0 -1
  155. package/dist/helper/TidUtils.d.ts +0 -4
  156. package/dist/helper/TidUtils.js +0 -171
  157. package/dist/helper/TidUtils.js.map +0 -1
  158. package/dist/services/internal/TidService.d.ts +0 -43
  159. package/dist/services/internal/TidService.js +0 -156
  160. package/dist/services/internal/TidService.js.map +0 -1
  161. package/dist/types/auth/TidDynamicArgs.d.ts +0 -10
  162. package/dist/types/auth/TidDynamicArgs.js +0 -3
  163. package/dist/types/auth/TidDynamicArgs.js.map +0 -1
  164. package/dist/types/auth/TidHeader.d.ts +0 -8
  165. package/dist/types/auth/TidHeader.js +0 -3
  166. package/dist/types/auth/TidHeader.js.map +0 -1
  167. package/dist/types/auth/TidParams.d.ts +0 -27
  168. package/dist/types/auth/TidParams.js +0 -3
  169. package/dist/types/auth/TidParams.js.map +0 -1
  170. package/dist/types/auth/TidProvider.d.ts +0 -18
  171. package/dist/types/auth/TidProvider.js +0 -3
  172. package/dist/types/auth/TidProvider.js.map +0 -1
  173. package/src/helper/TidUtils.ts +0 -198
  174. package/src/services/internal/TidService.ts +0 -140
  175. package/src/types/auth/TidDynamicArgs.ts +0 -10
  176. package/src/types/auth/TidHeader.ts +0 -12
  177. package/src/types/auth/TidParams.ts +0 -36
  178. package/src/types/auth/TidProvider.ts +0 -19
@@ -1,5 +1,5 @@
1
- import { ENotificationType } from '../../enums/Notification';
2
- import { ERawNotificationType } from '../../enums/raw/Notification';
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?: ENotificationType;
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(ERawNotificationType, notification.icon.id);
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
- ? ENotificationType[notificationType as keyof typeof ENotificationType]
44
- : ENotificationType.UNDEFINED;
43
+ ? NotificationType[notificationType as keyof typeof NotificationType]
44
+ : NotificationType.UNDEFINED;
45
45
  }
46
46
 
47
47
  /** The raw notification details. */
@@ -1,6 +1,6 @@
1
- import { ELogActions } from '../../enums/Logging';
2
- import { EMediaType } from '../../enums/Media';
3
- import { ERawMediaType } from '../../enums/raw/Media';
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.getQuotedTweet(tweet);
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.getRetweetedTweet(tweet);
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 getQuotedTweet(tweet: IRawTweet): Tweet | undefined {
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 getRetweetedTweet(tweet: IRawTweet): Tweet | undefined {
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(ELogActions.DESERIALIZE, { id: item.rest_id });
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(ELogActions.WARNING, {
150
- action: ELogActions.DESERIALIZE,
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(ELogActions.DESERIALIZE, { id: item.rest_id });
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(ELogActions.WARNING, {
188
- action: ELogActions.DESERIALIZE,
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(ELogActions.DESERIALIZE, { id: (item.tweet_results.result as IRawTweet).rest_id });
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(ELogActions.WARNING, {
232
- action: ELogActions.DESERIALIZE,
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: EMediaType;
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 == ERawMediaType.PHOTO) {
342
- this.type = EMediaType.PHOTO;
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 == ERawMediaType.GIF) {
347
- this.type = EMediaType.GIF;
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 = EMediaType.VIDEO;
352
+ this.type = MediaType.VIDEO;
353
353
  this.thumbnailUrl = media.media_url_https;
354
354
 
355
355
  /** The highest bitrate of all variants. */
@@ -1,4 +1,4 @@
1
- import { ELogActions } from '../../enums/Logging';
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(ELogActions.DESERIALIZE, { id: item.rest_id });
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(ELogActions.WARNING, {
82
- action: ELogActions.DESERIALIZE,
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(ELogActions.DESERIALIZE, { id: item.rest_id });
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(ELogActions.WARNING, {
119
- action: ELogActions.DESERIALIZE,
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(ELogActions.DESERIALIZE, { id: item.user_results.result.rest_id });
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(ELogActions.WARNING, {
151
- action: ELogActions.DESERIALIZE,
150
+ LogService.log(LogActions.WARNING, {
151
+ action: LogActions.DESERIALIZE,
152
152
  message: `User not found, skipping`,
153
153
  });
154
154
  }
@@ -1,6 +1,6 @@
1
1
  import { AxiosRequestConfig } from 'axios';
2
2
 
3
- import { ERawTweetRepliesSortType, ERawTweetSearchResultType } from '../enums/raw/Tweet';
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?: ERawTweetRepliesSortType): AxiosRequestConfig {
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 ?? ERawTweetRepliesSortType.RELEVACE,
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 ? ERawTweetSearchResultType.TOP : ERawTweetSearchResultType.LATEST,
454
+ product: parsedFilter.top ? RawTweetSearchResultType.TOP : RawTweetSearchResultType.LATEST,
455
455
  withAuxiliaryUserLabels: false,
456
456
  withArticleRichContentState: false,
457
457
  withArticlePlainText: false,
@@ -2,7 +2,7 @@ import qs from 'querystring';
2
2
 
3
3
  import { AxiosRequestConfig } from 'axios';
4
4
 
5
- import { ERawAnalyticsGranularity, ERawAnalyticsMetric } from '../enums/raw/Analytics';
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: ERawAnalyticsGranularity,
81
- requestedMetrics: ERawAnalyticsMetric[],
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 { EApiErrors } from '../../enums/Api';
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(EApiErrors.BAD_AUTHENTICATION);
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 handleAxiosError(error: AxiosError<IRawErrorData | IRawErrorDetails>): void {
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 handleUnknownError(): void {
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.handleAxiosError(error as AxiosError<IRawErrorData | IRawErrorDetails>);
36
+ this._handleAxiosError(error as AxiosError<IRawErrorData | IRawErrorDetails>);
37
37
  } else {
38
- this.handleUnknownError();
38
+ this._handleUnknownError();
39
39
  }
40
40
  }
41
41
  }
@@ -1,4 +1,4 @@
1
- import { ELogActions } from '../../enums/Logging';
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: ELogActions, data: NonNullable<unknown>): void {
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
- import axios from 'axios';
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 { allowGuestAuthentication, fetchResources, postResources } from '../../collections/Groups';
5
- import { requests } from '../../collections/Requests';
6
- import { EApiErrors } from '../../enums/Api';
7
- import { ELogActions } from '../../enums/Logging';
8
- import { EResourceType } from '../../enums/Resource';
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 { ITidHeader } from '../../types/auth/TidHeader';
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 checkAuthorization(resource: EResourceType): void {
64
+ private _checkAuthorization(resource: ResourceType): void {
69
65
  // Logging
70
- LogService.log(ELogActions.AUTHORIZATION, { authenticated: this.config.userId != undefined });
66
+ LogService.log(LogActions.AUTHORIZATION, { authenticated: this.config.userId != undefined });
71
67
 
72
68
  // Checking authorization status
73
- if (!allowGuestAuthentication.includes(resource) && this.config.userId == undefined) {
74
- throw new Error(EApiErrors.RESOURCE_NOT_ALLOWED);
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 getCredential(): Promise<AuthCredential> {
79
+ private async _getCredential(): Promise<AuthCredential> {
84
80
  if (this.config.apiKey) {
85
81
  // Logging
86
- LogService.log(ELogActions.GET, { target: 'USER_CREDENTIAL' });
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(ELogActions.GET, { target: 'NEW_GUEST_CREDENTIAL' });
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 getTransactionHeader(method: string, url: string): Promise<ITidHeader | undefined> {
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 this._tidProvider.generate(method.toUpperCase(), path);
115
-
116
- if (tid) {
117
- return {
118
- /* eslint-disable @typescript-eslint/naming-convention */
119
- 'x-client-transaction-id': tid,
120
- /* eslint-enable @typescript-eslint/naming-convention */
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 validateArgs(resource: EResourceType, args: IFetchArgs | IPostArgs): FetchArgs | PostArgs | undefined {
136
- if (fetchResources.includes(resource)) {
133
+ private _validateArgs(resource: ResourceType, args: IFetchArgs | IPostArgs): FetchArgs | PostArgs | undefined {
134
+ if (FetchResourcesGroup.includes(resource)) {
137
135
  // Logging
138
- LogService.log(ELogActions.VALIDATE, { target: 'FETCH_ARGS' });
136
+ LogService.log(LogActions.VALIDATE, { target: 'FETCH_ARGS' });
139
137
 
140
138
  return new FetchArgs(args);
141
- } else if (postResources.includes(resource)) {
139
+ } else if (PostResourcesGroup.includes(resource)) {
142
140
  // Logging
143
- LogService.log(ELogActions.VALIDATE, { target: 'POST_ARGS' });
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 wait(): Promise<void> {
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: EResourceType, args: IFetchArgs | IPostArgs): Promise<T> {
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(ELogActions.REQUEST, { resource: resource, args: args });
207
+ LogService.log(LogActions.REQUEST, { resource: resource, args: args });
204
208
 
205
209
  // Checking authorization for the requested resource
206
- this.checkAuthorization(resource);
210
+ this._checkAuthorization(resource);
207
211
 
208
212
  // Validating args
209
- args = this.validateArgs(resource, args)!;
213
+ args = this._validateArgs(resource, args)!;
210
214
 
211
215
  // Getting credentials from key
212
- const cred: AuthCredential = await this.getCredential();
216
+ const cred: AuthCredential = await this._getCredential();
213
217
 
214
218
  // Getting request configuration
215
- const config = requests[resource](args);
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
- // Sending the request
229
- try {
230
- // Introducing a delay
231
- await this.wait();
232
-
233
- // Returning the reponse body
234
- return (await axios<T>(config)).data;
235
- } catch (error) {
236
- // If error, delegate handling to error handler
237
- this._errorHandler.handle(error);
238
- throw error;
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 { extractors } from '../../collections/Extractors';
2
- import { EResourceType } from '../../enums/Resource';
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: EResourceType = EResourceType.LIST_MEMBERS;
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 = extractors[resource](response);
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 = EResourceType.LIST_TWEETS;
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 = extractors[resource](response);
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());