@glagan/rettiwt-api 7.0.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.
Files changed (165) hide show
  1. package/.eslintrc.js +166 -0
  2. package/.gitattributes +3 -0
  3. package/.github/FUNDING.yml +4 -0
  4. package/.github/ISSUE_TEMPLATE/bug-report.yml +57 -0
  5. package/.github/ISSUE_TEMPLATE/feature-request.yml +20 -0
  6. package/.github/ISSUE_TEMPLATE/question.yml +15 -0
  7. package/.github/PULL_REQUEST_TEMPLATE.md +32 -0
  8. package/.github/workflows/ci.yml +32 -0
  9. package/.github/workflows/publish.yml +23 -0
  10. package/.nvmrc +1 -0
  11. package/.prettierignore +3 -0
  12. package/.prettierrc +13 -0
  13. package/LICENSE +21 -0
  14. package/README.md +566 -0
  15. package/dist/cli.js +43 -0
  16. package/eslint.config.mjs +17 -0
  17. package/package.json +50 -0
  18. package/src/Rettiwt.ts +97 -0
  19. package/src/cli.ts +48 -0
  20. package/src/collections/Extractors.ts +155 -0
  21. package/src/collections/Groups.ts +81 -0
  22. package/src/collections/Requests.ts +89 -0
  23. package/src/collections/Tweet.ts +17 -0
  24. package/src/commands/DirectMessage.ts +62 -0
  25. package/src/commands/List.ts +90 -0
  26. package/src/commands/Tweet.ts +437 -0
  27. package/src/commands/User.ts +367 -0
  28. package/src/enums/Api.ts +10 -0
  29. package/src/enums/Authentication.ts +10 -0
  30. package/src/enums/Data.ts +13 -0
  31. package/src/enums/Logging.ts +14 -0
  32. package/src/enums/Media.ts +10 -0
  33. package/src/enums/Notification.ts +12 -0
  34. package/src/enums/Resource.ts +69 -0
  35. package/src/enums/Tweet.ts +8 -0
  36. package/src/enums/raw/Analytics.ts +32 -0
  37. package/src/enums/raw/Media.ts +10 -0
  38. package/src/enums/raw/Notification.ts +11 -0
  39. package/src/enums/raw/Tweet.ts +20 -0
  40. package/src/helper/CliUtils.ts +17 -0
  41. package/src/helper/JsonUtils.ts +70 -0
  42. package/src/index.ts +128 -0
  43. package/src/models/RettiwtConfig.ts +101 -0
  44. package/src/models/args/FetchArgs.ts +169 -0
  45. package/src/models/args/PostArgs.ts +93 -0
  46. package/src/models/args/ProfileArgs.ts +68 -0
  47. package/src/models/auth/AuthCookie.ts +58 -0
  48. package/src/models/auth/AuthCredential.ts +83 -0
  49. package/src/models/data/Analytics.ts +97 -0
  50. package/src/models/data/BookmarkFolder.ts +73 -0
  51. package/src/models/data/Conversation.ts +344 -0
  52. package/src/models/data/CursoredData.ts +64 -0
  53. package/src/models/data/DirectMessage.ts +335 -0
  54. package/src/models/data/Inbox.ts +124 -0
  55. package/src/models/data/List.ts +113 -0
  56. package/src/models/data/Notification.ts +84 -0
  57. package/src/models/data/Tweet.ts +388 -0
  58. package/src/models/data/User.ts +187 -0
  59. package/src/models/errors/TwitterError.ts +65 -0
  60. package/src/models/params/Variables.ts +62 -0
  61. package/src/requests/DirectMessage.ts +229 -0
  62. package/src/requests/List.ts +203 -0
  63. package/src/requests/Media.ts +67 -0
  64. package/src/requests/Tweet.ts +607 -0
  65. package/src/requests/User.ts +1191 -0
  66. package/src/services/internal/AuthService.ts +115 -0
  67. package/src/services/internal/ErrorService.ts +41 -0
  68. package/src/services/internal/LogService.ts +34 -0
  69. package/src/services/public/DirectMessageService.ts +159 -0
  70. package/src/services/public/FetcherService.ts +366 -0
  71. package/src/services/public/ListService.ts +241 -0
  72. package/src/services/public/TweetService.ts +886 -0
  73. package/src/services/public/UserService.ts +1154 -0
  74. package/src/types/ErrorHandler.ts +13 -0
  75. package/src/types/Fetch.ts +3 -0
  76. package/src/types/RettiwtConfig.ts +48 -0
  77. package/src/types/args/FetchArgs.ts +233 -0
  78. package/src/types/args/PostArgs.ts +142 -0
  79. package/src/types/args/ProfileArgs.ts +33 -0
  80. package/src/types/auth/AuthCookie.ts +22 -0
  81. package/src/types/auth/AuthCredential.ts +28 -0
  82. package/src/types/auth/TransactionHeader.ts +8 -0
  83. package/src/types/data/Analytics.ts +58 -0
  84. package/src/types/data/BookmarkFolder.ts +12 -0
  85. package/src/types/data/Conversation.ts +44 -0
  86. package/src/types/data/CursoredData.ts +24 -0
  87. package/src/types/data/DirectMessage.ts +33 -0
  88. package/src/types/data/Inbox.ts +23 -0
  89. package/src/types/data/List.ts +33 -0
  90. package/src/types/data/Notification.ts +26 -0
  91. package/src/types/data/Tweet.ts +99 -0
  92. package/src/types/data/User.ts +54 -0
  93. package/src/types/errors/TwitterError.ts +37 -0
  94. package/src/types/params/Variables.ts +41 -0
  95. package/src/types/raw/base/Analytic.ts +32 -0
  96. package/src/types/raw/base/BookmarkFolder.ts +12 -0
  97. package/src/types/raw/base/Cursor.ts +13 -0
  98. package/src/types/raw/base/Error.ts +38 -0
  99. package/src/types/raw/base/LimitedVisibilityTweet.ts +40 -0
  100. package/src/types/raw/base/List.ts +50 -0
  101. package/src/types/raw/base/Media.ts +53 -0
  102. package/src/types/raw/base/Message.ts +22 -0
  103. package/src/types/raw/base/Notification.ts +66 -0
  104. package/src/types/raw/base/Space.ts +35 -0
  105. package/src/types/raw/base/Tweet.ts +139 -0
  106. package/src/types/raw/base/User.ts +182 -0
  107. package/src/types/raw/composite/DataResult.ts +8 -0
  108. package/src/types/raw/composite/TimelineList.ts +10 -0
  109. package/src/types/raw/composite/TimelineTweet.ts +14 -0
  110. package/src/types/raw/composite/TimelineUser.ts +13 -0
  111. package/src/types/raw/dm/Conversation.ts +59 -0
  112. package/src/types/raw/dm/InboxInitial.ts +155 -0
  113. package/src/types/raw/dm/InboxTimeline.ts +301 -0
  114. package/src/types/raw/dm/UserUpdates.ts +46 -0
  115. package/src/types/raw/generic/Response.ts +10 -0
  116. package/src/types/raw/list/AddMember.ts +175 -0
  117. package/src/types/raw/list/Details.ts +176 -0
  118. package/src/types/raw/list/Members.ts +154 -0
  119. package/src/types/raw/list/RemoveMember.ts +174 -0
  120. package/src/types/raw/list/Tweets.ts +2296 -0
  121. package/src/types/raw/media/FinalizeUpload.ts +20 -0
  122. package/src/types/raw/media/InitalizeUpload.ts +12 -0
  123. package/src/types/raw/media/LiveVideoStream.ts +21 -0
  124. package/src/types/raw/space/Details.ts +359 -0
  125. package/src/types/raw/tweet/Bookmark.ts +14 -0
  126. package/src/types/raw/tweet/Details.ts +210 -0
  127. package/src/types/raw/tweet/DetailsBulk.ts +338 -0
  128. package/src/types/raw/tweet/Like.ts +14 -0
  129. package/src/types/raw/tweet/Likers.ts +200 -0
  130. package/src/types/raw/tweet/Post.ts +150 -0
  131. package/src/types/raw/tweet/Replies.ts +539 -0
  132. package/src/types/raw/tweet/Retweet.ts +31 -0
  133. package/src/types/raw/tweet/Retweeters.ts +208 -0
  134. package/src/types/raw/tweet/Schedule.ts +18 -0
  135. package/src/types/raw/tweet/Search.ts +597 -0
  136. package/src/types/raw/tweet/Unbookmark.ts +14 -0
  137. package/src/types/raw/tweet/Unlike.ts +14 -0
  138. package/src/types/raw/tweet/Unpost.ts +20 -0
  139. package/src/types/raw/tweet/Unretweet.ts +31 -0
  140. package/src/types/raw/tweet/Unschedule.ts +14 -0
  141. package/src/types/raw/user/Affiliates.ts +179 -0
  142. package/src/types/raw/user/Analytics.ts +23 -0
  143. package/src/types/raw/user/BookmarkFolderTweets.ts +53 -0
  144. package/src/types/raw/user/BookmarkFolders.ts +41 -0
  145. package/src/types/raw/user/Bookmarks.ts +637 -0
  146. package/src/types/raw/user/Details.ts +185 -0
  147. package/src/types/raw/user/DetailsBulk.ts +104 -0
  148. package/src/types/raw/user/Follow.ts +280 -0
  149. package/src/types/raw/user/Followed.ts +1942 -0
  150. package/src/types/raw/user/Followers.ts +215 -0
  151. package/src/types/raw/user/Following.ts +215 -0
  152. package/src/types/raw/user/Highlights.ts +1287 -0
  153. package/src/types/raw/user/Likes.ts +1254 -0
  154. package/src/types/raw/user/Lists.ts +378 -0
  155. package/src/types/raw/user/Media.ts +1738 -0
  156. package/src/types/raw/user/Notifications.ts +499 -0
  157. package/src/types/raw/user/ProfileUpdate.ts +80 -0
  158. package/src/types/raw/user/Recommended.ts +2319 -0
  159. package/src/types/raw/user/Scheduled.ts +37 -0
  160. package/src/types/raw/user/Search.ts +230 -0
  161. package/src/types/raw/user/Subscriptions.ts +176 -0
  162. package/src/types/raw/user/Tweets.ts +1254 -0
  163. package/src/types/raw/user/TweetsAndReplies.ts +1254 -0
  164. package/src/types/raw/user/Unfollow.ts +280 -0
  165. package/tsconfig.json +97 -0
@@ -0,0 +1,115 @@
1
+ import { ofetch } from 'ofetch';
2
+
3
+ import { ApiErrors } from '../../enums/Api';
4
+ import { AuthCredential } from '../../models/auth/AuthCredential';
5
+ import { RettiwtConfig } from '../../models/RettiwtConfig';
6
+
7
+ /**
8
+ * The services that handles authentication.
9
+ *
10
+ * @internal
11
+ */
12
+ export class AuthService {
13
+ /** The config object. */
14
+ private readonly _config: RettiwtConfig;
15
+
16
+ /**
17
+ * @param config - The config for Rettiwt.
18
+ */
19
+ public constructor(config: RettiwtConfig) {
20
+ this._config = config;
21
+ }
22
+
23
+ /**
24
+ * Decodes the encoded cookie string.
25
+ *
26
+ * @param encodedCookies - The encoded cookie string to decode.
27
+ * @returns The decoded cookie string.
28
+ */
29
+ public static decodeCookie(encodedCookies: string): string {
30
+ // Decoding the encoded cookie string
31
+ const decodedCookies: string = Buffer.from(encodedCookies, 'base64').toString('ascii');
32
+
33
+ return decodedCookies;
34
+ }
35
+
36
+ /**
37
+ * Encodes the given cookie string.
38
+ *
39
+ * @param cookieString - The cookie string to encode.
40
+ * @returns The encoded cookie string.
41
+ */
42
+ public static encodeCookie(cookieString: string): string {
43
+ // Encoding the cookie string to base64
44
+ const encodedCookies: string = Buffer.from(cookieString).toString('base64');
45
+
46
+ return encodedCookies;
47
+ }
48
+
49
+ /**
50
+ * Gets the user's id from the given API key.
51
+ *
52
+ * @param apiKey - The API key.
53
+ * @returns The user id associated with the API key.
54
+ */
55
+ public static getUserId(apiKey: string): string {
56
+ // Getting the cookie string from the API key
57
+ const cookieString: string = AuthService.decodeCookie(apiKey);
58
+
59
+ // Searching for the user id in the cookie string
60
+ const searchResults: string[] | null = cookieString.match(
61
+ /((?<=twid="u=)(\d+)(?="))|((?<=twid=u%3D)(\d+)(?=;))/,
62
+ );
63
+
64
+ // If user id was found
65
+ if (searchResults) {
66
+ return searchResults[0];
67
+ }
68
+ // If user id was not found
69
+ else {
70
+ throw new Error(ApiErrors.BAD_AUTHENTICATION);
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Login to twitter as guest.
76
+ *
77
+ * @returns A new guest key.
78
+ *
79
+ * @example
80
+ * ```
81
+ * import { Rettiwt } from 'rettiwt-api';
82
+ *
83
+ * // Creating a new Rettiwt instance
84
+ * const rettiwt = new Rettiwt();
85
+ *
86
+ * // Logging in an getting a new guest key
87
+ * rettiwt.auth.guest()
88
+ * .then(guestKey => {
89
+ * // Use the guest key
90
+ * ...
91
+ * })
92
+ * .catch(err => {
93
+ * console.log(err);
94
+ * });
95
+ * ```
96
+ */
97
+ public async guest(): Promise<AuthCredential> {
98
+ // Creating a new blank credential
99
+ const cred: AuthCredential = new AuthCredential();
100
+
101
+ // Getting the guest token
102
+ const data = await ofetch<{
103
+ /* eslint-disable @typescript-eslint/naming-convention */
104
+ guest_token: string;
105
+ /* eslint-enable @typescript-eslint/naming-convention */
106
+ }>('https://api.twitter.com/1.1/guest/activate.json', {
107
+ method: 'post',
108
+ headers: cred.toHeader(),
109
+ agent: this._config.httpsAgent,
110
+ });
111
+ cred.guestToken = data.guest_token;
112
+
113
+ return cred;
114
+ }
115
+ }
@@ -0,0 +1,41 @@
1
+ import { FetchError } from 'ofetch';
2
+
3
+ import { TwitterError } from '../../models/errors/TwitterError';
4
+ import { IErrorHandler } from '../../types/ErrorHandler';
5
+ import { IErrorData as IRawErrorData, IErrorDetails as IRawErrorDetails } from '../../types/raw/base/Error';
6
+
7
+ /**
8
+ * The base service that handles any errors.
9
+ *
10
+ * @public
11
+ */
12
+ export class ErrorService implements IErrorHandler {
13
+ /**
14
+ * Handles errors thrown by Twitter.
15
+ *
16
+ * @param error - The error response received from Twitter.
17
+ */
18
+ private _handleFetchError(error: FetchError<IRawErrorData | IRawErrorDetails>): void {
19
+ throw new TwitterError(error);
20
+ }
21
+
22
+ /**
23
+ * Handle unknown error.
24
+ */
25
+ private _handleUnknownError(error: unknown): void {
26
+ throw error;
27
+ }
28
+
29
+ /**
30
+ * The method called when an error response is received from Twitter API.
31
+ *
32
+ * @param error - The error caught while making HTTP request to Twitter API.
33
+ */
34
+ public handle(error: unknown): void {
35
+ if (error instanceof FetchError) {
36
+ this._handleFetchError(error as FetchError<IRawErrorData | IRawErrorDetails>);
37
+ } else {
38
+ this._handleUnknownError(error);
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,34 @@
1
+ import { LogActions } from '../../enums/Logging';
2
+
3
+ /**
4
+ * Handles logging of data for debug purpose.
5
+ *
6
+ * @internal
7
+ */
8
+ export class LogService {
9
+ /** Whether logging is enabled or not. */
10
+ public static enabled = false;
11
+
12
+ /**
13
+ * Logs the given data.
14
+ *
15
+ * @param action - The action to be logged.
16
+ *
17
+ * @param data - The data to be logged.
18
+ */
19
+ public static log(action: LogActions, data: NonNullable<unknown>): void {
20
+ // Proceed to log only if logging is enabled
21
+ if (this.enabled) {
22
+ // Preparing the log message
23
+ const logPrefix = 'Rettiwt-API';
24
+ const logTime: string = new Date().toISOString();
25
+ const logAction: string = action;
26
+ const logData: string = JSON.stringify(data);
27
+
28
+ const logMessage = `[${logPrefix}] [${logTime}] [${logAction}] ${logData}`;
29
+
30
+ // Logging
31
+ console.log(logMessage);
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,159 @@
1
+ import { Extractors } from '../../collections/Extractors';
2
+ import { ResourceType } from '../../enums/Resource';
3
+ import { Conversation } from '../../models/data/Conversation';
4
+ import { Inbox } from '../../models/data/Inbox';
5
+ import { RettiwtConfig } from '../../models/RettiwtConfig';
6
+ import { IConversationTimelineResponse } from '../../types/raw/dm/Conversation';
7
+ import { IInboxInitialResponse } from '../../types/raw/dm/InboxInitial';
8
+ import { IInboxTimelineResponse } from '../../types/raw/dm/InboxTimeline';
9
+
10
+ import { FetcherService } from './FetcherService';
11
+
12
+ /**
13
+ * Handles interacting with resources related to direct messages
14
+ *
15
+ * @public
16
+ */
17
+ export class DirectMessageService extends FetcherService {
18
+ /**
19
+ * @param config - The config object for configuring the Rettiwt instance.
20
+ *
21
+ * @internal
22
+ */
23
+ public constructor(config: RettiwtConfig) {
24
+ super(config);
25
+ }
26
+
27
+ /**
28
+ * Get the full conversation history for a specific conversation, ordered recent to oldest.
29
+ * Use this to load complete message history for a conversation identified from the inbox.
30
+ *
31
+ * @param conversationId - The ID of the conversation (e.g., "394028042-1712730991884689408").
32
+ * @param cursor - The cursor for pagination. Is equal to the ID of the last message from previous batch.
33
+ *
34
+ * @returns The conversation with full message history, or undefined if not found.
35
+ *
36
+ * @example
37
+ *
38
+ * ```ts
39
+ * import { Rettiwt } from 'rettiwt-api';
40
+ *
41
+ * // Creating a new Rettiwt instance using the given 'API_KEY'
42
+ * const rettiwt = new Rettiwt({ apiKey: API_KEY });
43
+ *
44
+ * // Fetching a specific conversation
45
+ * rettiwt.dm.conversation('394028042-1712730991884689408')
46
+ * .then(conversation => {
47
+ * if (conversation) {
48
+ * console.log(`Conversation with ${conversation.participants.length} participants`);
49
+ * console.log(`${conversation.messages.length} messages loaded`);
50
+ * }
51
+ * })
52
+ * .catch(err => {
53
+ * console.log(err);
54
+ * });
55
+ * ```
56
+ */
57
+ public async conversation(conversationId: string, cursor?: string): Promise<Conversation | undefined> {
58
+ const resource = ResourceType.DM_CONVERSATION;
59
+
60
+ // Fetching raw conversation timeline
61
+ const response = await this.request<IConversationTimelineResponse>(resource, {
62
+ conversationId,
63
+ maxId: cursor,
64
+ });
65
+
66
+ // Deserializing response
67
+ const data = Extractors[resource](response);
68
+
69
+ return data;
70
+ }
71
+
72
+ /**
73
+ * Delete a conversation.
74
+ * You will leave the conversation and it will be removed from your inbox.
75
+ *
76
+ * @param conversationId - The ID of the conversation to delete.
77
+ *
78
+ * @returns A promise that resolves when the conversation is deleted.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * import { Rettiwt } from 'rettiwt-api';
83
+ *
84
+ * // Creating a new Rettiwt instance using the given 'API_KEY'
85
+ * const rettiwt = new Rettiwt({ apiKey: API_KEY });
86
+ * // Deleting a conversation
87
+ * rettiwt.dm.deleteConversation('394028042-1712730991884689408')
88
+ * .then(() => {
89
+ * console.log('Conversation deleted successfully');
90
+ * })
91
+ * .catch(err => {
92
+ * console.log('Failed to delete conversation:', err);
93
+ * });
94
+ * ```
95
+ **/
96
+ public async deleteConversation(conversationId: string): Promise<void> {
97
+ const resource = ResourceType.DM_DELETE_CONVERSATION;
98
+
99
+ // Sending delete request
100
+ await this.request<void>(resource, {
101
+ conversationId,
102
+ });
103
+ }
104
+
105
+ /**
106
+ * Get your inbox, ordered recent to oldest.
107
+ *
108
+ * @param cursor - The cursor to the inbox items to fetch. Is equal to the ID of the last inbox conversation.
109
+ *
110
+ * @returns The required inbox. Returns initial inbox if no cursor is provided.
111
+ *
112
+ * @example
113
+ *
114
+ * ```ts
115
+ * import { Rettiwt } from 'rettiwt-api';
116
+ *
117
+ * // Creating a new Rettiwt instance using the given 'API_KEY'
118
+ * const rettiwt = new Rettiwt({ apiKey: API_KEY });
119
+ *
120
+ * // Fetching the initial DM inbox state
121
+ * rettiwt.dm.inbox()
122
+ * .then(inbox => {
123
+ * console.log(`Found ${inbox.conversations.length} conversations`);
124
+ * console.log('First conversation:', inbox.conversations[0]);
125
+ * })
126
+ * .catch(err => {
127
+ * console.log(err);
128
+ * });
129
+ * ```
130
+ */
131
+ public async inbox(cursor?: string): Promise<Inbox> {
132
+ // If cursor is provided, fetch initial inbox
133
+ if (cursor !== undefined) {
134
+ const resource = ResourceType.DM_INBOX_TIMELINE;
135
+
136
+ // Fetching raw inbox timeline
137
+ const response = await this.request<IInboxTimelineResponse>(resource, {
138
+ maxId: cursor,
139
+ });
140
+
141
+ // Deserializing response
142
+ const data = Extractors[resource](response);
143
+
144
+ return data;
145
+ }
146
+ // Else, fetch next inbox data
147
+ else {
148
+ const resource = ResourceType.DM_INBOX_INITIAL_STATE;
149
+
150
+ // Fetching raw inbox initial state
151
+ const response = await this.request<IInboxInitialResponse>(resource, {});
152
+
153
+ // Deserializing response
154
+ const data = Extractors[resource](response);
155
+
156
+ return data;
157
+ }
158
+ }
159
+ }