rettiwt-api 6.0.7 → 6.1.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 (220) hide show
  1. package/.github/ISSUE_TEMPLATE/bug-report.yml +57 -0
  2. package/.github/ISSUE_TEMPLATE/feature-request.yml +20 -0
  3. package/.github/ISSUE_TEMPLATE/question.yml +15 -0
  4. package/.github/PULL_REQUEST_TEMPLATE.md +32 -0
  5. package/.github/workflows/ci.yml +33 -0
  6. package/.nvmrc +1 -0
  7. package/README.md +30 -6
  8. package/dist/Rettiwt.d.ts +3 -0
  9. package/dist/Rettiwt.js +4 -0
  10. package/dist/Rettiwt.js.map +1 -1
  11. package/dist/cli.js +2 -0
  12. package/dist/cli.js.map +1 -1
  13. package/dist/collections/Extractors.d.ts +24 -0
  14. package/dist/collections/Extractors.js +14 -0
  15. package/dist/collections/Extractors.js.map +1 -1
  16. package/dist/collections/Groups.js +11 -0
  17. package/dist/collections/Groups.js.map +1 -1
  18. package/dist/collections/Requests.js +12 -0
  19. package/dist/collections/Requests.js.map +1 -1
  20. package/dist/commands/DirectMessage.d.ts +10 -0
  21. package/dist/commands/DirectMessage.js +57 -0
  22. package/dist/commands/DirectMessage.js.map +1 -0
  23. package/dist/commands/List.js +44 -3
  24. package/dist/commands/List.js.map +1 -1
  25. package/dist/commands/Tweet.js +29 -1
  26. package/dist/commands/Tweet.js.map +1 -1
  27. package/dist/commands/User.js +39 -1
  28. package/dist/commands/User.js.map +1 -1
  29. package/dist/enums/Data.d.ts +3 -1
  30. package/dist/enums/Data.js +2 -0
  31. package/dist/enums/Data.js.map +1 -1
  32. package/dist/enums/Resource.d.ts +11 -0
  33. package/dist/enums/Resource.js +12 -0
  34. package/dist/enums/Resource.js.map +1 -1
  35. package/dist/enums/raw/Analytics.d.ts +6 -3
  36. package/dist/enums/raw/Analytics.js +5 -2
  37. package/dist/enums/raw/Analytics.js.map +1 -1
  38. package/dist/index.d.ts +15 -0
  39. package/dist/index.js +8 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/models/args/FetchArgs.d.ts +9 -0
  42. package/dist/models/args/FetchArgs.js +16 -0
  43. package/dist/models/args/FetchArgs.js.map +1 -1
  44. package/dist/models/args/PostArgs.d.ts +1 -0
  45. package/dist/models/args/PostArgs.js +2 -0
  46. package/dist/models/args/PostArgs.js.map +1 -1
  47. package/dist/models/data/Analytics.d.ts +43 -0
  48. package/dist/models/data/Analytics.js +92 -0
  49. package/dist/models/data/Analytics.js.map +1 -0
  50. package/dist/models/data/Conversation.d.ts +93 -0
  51. package/dist/models/data/Conversation.js +293 -0
  52. package/dist/models/data/Conversation.js.map +1 -0
  53. package/dist/models/data/CursoredData.d.ts +2 -1
  54. package/dist/models/data/CursoredData.js +6 -1
  55. package/dist/models/data/CursoredData.js.map +1 -1
  56. package/dist/models/data/DirectMessage.d.ts +105 -0
  57. package/dist/models/data/DirectMessage.js +284 -0
  58. package/dist/models/data/DirectMessage.js.map +1 -0
  59. package/dist/models/data/Inbox.d.ts +44 -0
  60. package/dist/models/data/Inbox.js +106 -0
  61. package/dist/models/data/Inbox.js.map +1 -0
  62. package/dist/models/data/List.d.ts +20 -0
  63. package/dist/models/data/List.js +50 -1
  64. package/dist/models/data/List.js.map +1 -1
  65. package/dist/models/data/Tweet.d.ts +6 -6
  66. package/dist/models/data/Tweet.js +4 -2
  67. package/dist/models/data/Tweet.js.map +1 -1
  68. package/dist/models/data/User.d.ts +2 -0
  69. package/dist/models/data/User.js +6 -0
  70. package/dist/models/data/User.js.map +1 -1
  71. package/dist/requests/DirectMessage.d.ts +28 -0
  72. package/dist/requests/DirectMessage.js +149 -0
  73. package/dist/requests/DirectMessage.js.map +1 -0
  74. package/dist/requests/List.d.ts +10 -0
  75. package/dist/requests/List.js +52 -0
  76. package/dist/requests/List.js.map +1 -1
  77. package/dist/requests/Tweet.d.ts +8 -0
  78. package/dist/requests/Tweet.js +30 -0
  79. package/dist/requests/Tweet.js.map +1 -1
  80. package/dist/requests/User.d.ts +8 -1
  81. package/dist/requests/User.js +67 -8
  82. package/dist/requests/User.js.map +1 -1
  83. package/dist/services/public/DirectMessageService.d.ts +100 -0
  84. package/dist/services/public/DirectMessageService.js +143 -0
  85. package/dist/services/public/DirectMessageService.js.map +1 -0
  86. package/dist/services/public/FetcherService.d.ts +3 -2
  87. package/dist/services/public/FetcherService.js +64 -3
  88. package/dist/services/public/FetcherService.js.map +1 -1
  89. package/dist/services/public/ListService.d.ts +85 -0
  90. package/dist/services/public/ListService.js +111 -0
  91. package/dist/services/public/ListService.js.map +1 -1
  92. package/dist/services/public/TweetService.d.ts +56 -0
  93. package/dist/services/public/TweetService.js +72 -0
  94. package/dist/services/public/TweetService.js.map +1 -1
  95. package/dist/services/public/UserService.d.ts +61 -2
  96. package/dist/services/public/UserService.js +89 -0
  97. package/dist/services/public/UserService.js.map +1 -1
  98. package/dist/types/args/FetchArgs.d.ts +69 -12
  99. package/dist/types/args/PostArgs.d.ts +29 -11
  100. package/dist/types/data/Analytics.d.ts +42 -0
  101. package/dist/types/data/Analytics.js +3 -0
  102. package/dist/types/data/Analytics.js.map +1 -0
  103. package/dist/types/data/Conversation.d.ts +32 -0
  104. package/dist/types/data/Conversation.js +3 -0
  105. package/dist/types/data/Conversation.js.map +1 -0
  106. package/dist/types/data/CursoredData.d.ts +4 -1
  107. package/dist/types/data/DirectMessage.d.ts +25 -0
  108. package/dist/types/data/DirectMessage.js +3 -0
  109. package/dist/types/data/DirectMessage.js.map +1 -0
  110. package/dist/types/data/Inbox.d.ts +18 -0
  111. package/dist/types/data/Inbox.js +3 -0
  112. package/dist/types/data/Inbox.js.map +1 -0
  113. package/dist/types/data/List.d.ts +5 -1
  114. package/dist/types/data/Tweet.d.ts +6 -6
  115. package/dist/types/data/User.d.ts +4 -0
  116. package/dist/types/raw/base/Analytic.d.ts +6 -1
  117. package/dist/types/raw/base/Message.d.ts +16 -0
  118. package/dist/types/raw/base/Message.js +4 -0
  119. package/dist/types/raw/base/Message.js.map +1 -0
  120. package/dist/types/raw/base/Tweet.d.ts +6 -6
  121. package/dist/types/raw/base/User.d.ts +2 -1
  122. package/dist/types/raw/composite/TimelineList.d.ts +9 -0
  123. package/dist/types/raw/composite/TimelineList.js +3 -0
  124. package/dist/types/raw/composite/TimelineList.js.map +1 -0
  125. package/dist/types/raw/dm/Conversation.d.ts +55 -0
  126. package/dist/types/raw/dm/Conversation.js +4 -0
  127. package/dist/types/raw/dm/Conversation.js.map +1 -0
  128. package/dist/types/raw/dm/InboxInitial.d.ts +137 -0
  129. package/dist/types/raw/dm/InboxInitial.js +4 -0
  130. package/dist/types/raw/dm/InboxInitial.js.map +1 -0
  131. package/dist/types/raw/dm/InboxTimeline.d.ts +287 -0
  132. package/dist/types/raw/dm/InboxTimeline.js +4 -0
  133. package/dist/types/raw/dm/InboxTimeline.js.map +1 -0
  134. package/dist/types/raw/dm/UserUpdates.d.ts +41 -0
  135. package/dist/types/raw/dm/UserUpdates.js +4 -0
  136. package/dist/types/raw/dm/UserUpdates.js.map +1 -0
  137. package/dist/types/raw/list/AddMember.d.ts +151 -0
  138. package/dist/types/raw/list/AddMember.js +4 -0
  139. package/dist/types/raw/list/AddMember.js.map +1 -0
  140. package/dist/types/raw/list/Details.d.ts +44 -13
  141. package/dist/types/raw/list/RemoveMember.d.ts +150 -0
  142. package/dist/types/raw/list/RemoveMember.js +4 -0
  143. package/dist/types/raw/list/RemoveMember.js.map +1 -0
  144. package/dist/types/raw/tweet/Bookmark.d.ts +12 -0
  145. package/dist/types/raw/tweet/Bookmark.js +4 -0
  146. package/dist/types/raw/tweet/Bookmark.js.map +1 -0
  147. package/dist/types/raw/tweet/Unbookmark.d.ts +11 -0
  148. package/dist/types/raw/tweet/Unbookmark.js +4 -0
  149. package/dist/types/raw/tweet/Unbookmark.js.map +1 -0
  150. package/dist/types/raw/user/Analytics.d.ts +6 -18
  151. package/dist/types/raw/user/Analytics.js +0 -1
  152. package/dist/types/raw/user/Analytics.js.map +1 -1
  153. package/dist/types/raw/user/Lists.d.ts +319 -0
  154. package/dist/types/raw/user/Lists.js +4 -0
  155. package/dist/types/raw/user/Lists.js.map +1 -0
  156. package/eslint.config.mjs +1 -1
  157. package/package.json +13 -6
  158. package/playground/.env.example +1 -0
  159. package/playground/README.md +53 -0
  160. package/playground/index.js +15 -0
  161. package/playground/package.json +15 -0
  162. package/src/Rettiwt.ts +5 -0
  163. package/src/cli.ts +2 -0
  164. package/src/collections/Extractors.ts +29 -0
  165. package/src/collections/Groups.ts +11 -0
  166. package/src/collections/Requests.ts +20 -0
  167. package/src/commands/DirectMessage.ts +62 -0
  168. package/src/commands/List.ts +44 -3
  169. package/src/commands/Tweet.ts +29 -1
  170. package/src/commands/User.ts +65 -1
  171. package/src/enums/Data.ts +2 -0
  172. package/src/enums/Resource.ts +13 -0
  173. package/src/enums/raw/Analytics.ts +5 -2
  174. package/src/index.ts +15 -0
  175. package/src/models/args/FetchArgs.ts +17 -0
  176. package/src/models/args/PostArgs.ts +2 -0
  177. package/src/models/data/Analytics.ts +97 -0
  178. package/src/models/data/Conversation.ts +344 -0
  179. package/src/models/data/CursoredData.ts +7 -2
  180. package/src/models/data/DirectMessage.ts +335 -0
  181. package/src/models/data/Inbox.ts +124 -0
  182. package/src/models/data/List.ts +60 -1
  183. package/src/models/data/Tweet.ts +10 -8
  184. package/src/models/data/User.ts +6 -0
  185. package/src/requests/DirectMessage.ts +233 -0
  186. package/src/requests/List.ts +58 -0
  187. package/src/requests/Tweet.ts +32 -0
  188. package/src/requests/User.ts +70 -7
  189. package/src/services/public/DirectMessageService.ts +159 -0
  190. package/src/services/public/FetcherService.ts +86 -4
  191. package/src/services/public/ListService.ts +127 -0
  192. package/src/services/public/TweetService.ts +82 -0
  193. package/src/services/public/UserService.ts +110 -2
  194. package/src/types/args/FetchArgs.ts +77 -12
  195. package/src/types/args/PostArgs.ts +31 -11
  196. package/src/types/data/Analytics.ts +58 -0
  197. package/src/types/data/Conversation.ts +44 -0
  198. package/src/types/data/CursoredData.ts +4 -1
  199. package/src/types/data/DirectMessage.ts +33 -0
  200. package/src/types/data/Inbox.ts +23 -0
  201. package/src/types/data/List.ts +7 -1
  202. package/src/types/data/Tweet.ts +6 -6
  203. package/src/types/data/User.ts +6 -0
  204. package/src/types/raw/base/Analytic.ts +7 -1
  205. package/src/types/raw/base/Message.ts +22 -0
  206. package/src/types/raw/base/Tweet.ts +6 -6
  207. package/src/types/raw/base/User.ts +2 -1
  208. package/src/types/raw/composite/TimelineList.ts +10 -0
  209. package/src/types/raw/dm/Conversation.ts +59 -0
  210. package/src/types/raw/dm/InboxInitial.ts +155 -0
  211. package/src/types/raw/dm/InboxTimeline.ts +301 -0
  212. package/src/types/raw/dm/UserUpdates.ts +46 -0
  213. package/src/types/raw/list/AddMember.ts +175 -0
  214. package/src/types/raw/list/Details.ts +52 -13
  215. package/src/types/raw/list/RemoveMember.ts +174 -0
  216. package/src/types/raw/tweet/Bookmark.ts +14 -0
  217. package/src/types/raw/tweet/Unbookmark.ts +14 -0
  218. package/src/types/raw/user/Analytics.ts +6 -22
  219. package/src/types/raw/user/Lists.ts +378 -0
  220. package/tsconfig.json +1 -1
@@ -0,0 +1,233 @@
1
+ import qs from 'querystring';
2
+
3
+ import { AxiosRequestConfig } from 'axios';
4
+
5
+ /**
6
+ * Common parameter sets for DM requests
7
+ */
8
+ const BaseDMParams = {
9
+ /* eslint-disable @typescript-eslint/naming-convention */
10
+
11
+ nsfw_filtering_enabled: false,
12
+ filter_low_quality: true,
13
+ include_quality: 'all',
14
+ dm_secret_conversations_enabled: false,
15
+ krs_registration_enabled: false,
16
+ cards_platform: 'Web-12',
17
+ include_cards: 1,
18
+ include_ext_alt_text: true,
19
+ include_ext_limited_action_results: true,
20
+ include_quote_count: true,
21
+ include_reply_count: 1,
22
+ tweet_mode: 'extended',
23
+ include_ext_views: true,
24
+ include_groups: true,
25
+ include_inbox_timelines: true,
26
+ include_ext_media_color: true,
27
+ supports_reactions: true,
28
+ supports_edit: true,
29
+ include_ext_edit_control: true,
30
+ include_ext_business_affiliations_label: true,
31
+ ext: 'mediaColor%2CaltText%2CbusinessAffiliationsLabel%2CmediaStats%2ChighlightedLabel%2CparodyCommentaryFanLabel%2CvoiceInfo%2CbirdwatchPivot%2CsuperFollowMetadata%2CunmentionInfo%2CeditControl%2Carticle',
32
+
33
+ /* eslint-enable @typescript-eslint/naming-convention */
34
+ };
35
+
36
+ const DMUserIncludeParams = {
37
+ /* eslint-disable @typescript-eslint/naming-convention */
38
+
39
+ include_profile_interstitial_type: 1,
40
+ include_blocking: 1,
41
+ include_blocked_by: 1,
42
+ include_followed_by: 1,
43
+ include_want_retweets: 1,
44
+ include_mute_edge: 1,
45
+ include_can_dm: 1,
46
+ include_can_media_tag: 1,
47
+ include_ext_is_blue_verified: 1,
48
+ include_ext_verified_type: 1,
49
+ include_ext_profile_image_shape: 1,
50
+ skip_status: 1,
51
+
52
+ /* eslint-enable @typescript-eslint/naming-convention */
53
+ };
54
+
55
+ /**
56
+ * Collection of requests related to direct messages.
57
+ *
58
+ * @public
59
+ */
60
+ export class DMRequests {
61
+ /**
62
+ * Get a specific DM conversation
63
+ * @param conversationId - The conversation ID (e.g., "394028042-1712730991884689408")
64
+ * @param maxId - Maximum ID for pagination (optional)
65
+ */
66
+ public static conversation(conversationId: string, maxId?: string): AxiosRequestConfig {
67
+ const context = maxId ? 'FETCH_DM_CONVERSATION_HISTORY' : 'FETCH_DM_CONVERSATION';
68
+
69
+ return {
70
+ method: 'get',
71
+ url: `https://x.com/i/api/1.1/dm/conversation/${conversationId}.json`,
72
+ params: {
73
+ ...BaseDMParams,
74
+ ...DMUserIncludeParams,
75
+ /* eslint-disable @typescript-eslint/naming-convention */
76
+ max_id: maxId,
77
+ context: context,
78
+ dm_users: false,
79
+ include_conversation_info: true,
80
+ /* eslint-enable @typescript-eslint/naming-convention */
81
+ },
82
+ paramsSerializer: { encode: encodeURIComponent },
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Delete a DM conversation
88
+ * @param conversationId - The ID of the conversation to delete
89
+ */
90
+ public static deleteConversation(conversationId: string): AxiosRequestConfig {
91
+ return {
92
+ method: 'post',
93
+ url: `https://x.com/i/api/1.1/dm/${conversationId}/delete.json`,
94
+ data: qs.stringify({
95
+ /* eslint-disable @typescript-eslint/naming-convention */
96
+ dm_secret_conversations_enabled: false,
97
+ krs_registration_enabled: false,
98
+ cards_platform: 'Web-12',
99
+ include_cards: 1,
100
+ include_ext_alt_text: true,
101
+ include_ext_limited_action_results: true,
102
+ include_quote_count: true,
103
+ include_reply_count: 1,
104
+ tweet_mode: 'extended',
105
+ include_ext_views: true,
106
+ dm_users: false,
107
+ include_groups: true,
108
+ include_inbox_timelines: true,
109
+ include_ext_media_color: true,
110
+ supports_reactions: true,
111
+ supports_edit: true,
112
+ include_conversation_info: true,
113
+ }),
114
+ };
115
+ }
116
+
117
+ /**
118
+ * Get the initial state of the DM inbox
119
+ */
120
+ public static inboxInitial(): AxiosRequestConfig {
121
+ return {
122
+ method: 'get',
123
+ url: 'https://x.com/i/api/1.1/dm/inbox_initial_state.json',
124
+ params: {
125
+ ...BaseDMParams,
126
+ ...DMUserIncludeParams,
127
+ /* eslint-disable @typescript-eslint/naming-convention */
128
+ dm_users: true,
129
+ include_ext_parody_commentary_fan_label: true,
130
+ ext: 'mediaColor%2CaltText%2CmediaStats%2ChighlightedLabel%2CparodyCommentaryFanLabel%2CvoiceInfo%2CbirdwatchPivot%2CsuperFollowMetadata%2CunmentionInfo%2CeditControl%2Carticle',
131
+ },
132
+ paramsSerializer: { encode: encodeURIComponent },
133
+ };
134
+ }
135
+
136
+ /**
137
+ * Get inbox timeline (pagination of conversations)
138
+ * @param maxId - Maximum ID for pagination
139
+ */
140
+ public static inboxTimeline(maxId?: string): AxiosRequestConfig {
141
+ return {
142
+ method: 'get',
143
+ url: 'https://x.com/i/api/1.1/dm/inbox_timeline/trusted.json',
144
+ params: {
145
+ ...BaseDMParams,
146
+ ...DMUserIncludeParams,
147
+ /* eslint-disable @typescript-eslint/naming-convention */
148
+ max_id: maxId,
149
+ dm_users: false,
150
+ },
151
+ paramsSerializer: { encode: encodeURIComponent },
152
+ };
153
+ }
154
+
155
+ /**
156
+ * Create a new DM or get DM creation interface
157
+ */
158
+ // public static new(): AxiosRequestConfig {
159
+ // return {
160
+ // method: 'get',
161
+ // url: 'https://x.com/i/api/1.1/dm/new2.json',
162
+ // params: {
163
+ // /* eslint-disable @typescript-eslint/naming-convention */
164
+ // ext: 'mediaColor%2CaltText%2CmediaStats%2ChighlightedLabel%2CparodyCommentaryFanLabel%2CvoiceInfo%2CbirdwatchPivot%2CsuperFollowMetadata%2CunmentionInfo%2CeditControl%2Carticle',
165
+ // include_ext_alt_text: true,
166
+ // include_ext_limited_action_results: true,
167
+ // include_reply_count: 1,
168
+ // tweet_mode: 'extended',
169
+ // include_ext_views: true,
170
+ // include_groups: true,
171
+ // include_inbox_timelines: true,
172
+ // include_ext_media_color: true,
173
+ // supports_reactions: true,
174
+ // supports_edit: true,
175
+ // },
176
+ // paramsSerializer: { encode: encodeURIComponent },
177
+ // };
178
+ // }
179
+
180
+ /**
181
+ * Check DM permissions for specific recipients
182
+ * @param recipientIds - Array of recipient user IDs
183
+ */
184
+ // public static permissions(recipientIds: string[]): AxiosRequestConfig {
185
+ // return {
186
+ // method: 'get',
187
+ // url: 'https://x.com/i/api/1.1/dm/permissions.json',
188
+ // params: {
189
+ // /* eslint-disable @typescript-eslint/naming-convention */
190
+ // recipient_ids: recipientIds.join(','),
191
+ // dm_users: true,
192
+ // },
193
+ // paramsSerializer: { encode: encodeURIComponent },
194
+ // };
195
+ // }
196
+
197
+ /**
198
+ * Update the last seen event ID for a conversation
199
+ * @param lastSeenEventId - The ID of the last seen event
200
+ * @param trustedLastSeenEventId - The trusted last seen event ID (usually same as lastSeenEventId)
201
+ */
202
+ // public static updateLastSeenEventId(lastSeenEventId: string, trustedLastSeenEventId?: string): AxiosRequestConfig {
203
+ // return {
204
+ // method: 'post',
205
+ // url: 'https://x.com/i/api/1.1/dm/update_last_seen_event_id.json',
206
+ // data: qs.stringify({
207
+ // /* eslint-disable @typescript-eslint/naming-convention */
208
+ // last_seen_event_id: lastSeenEventId,
209
+ // trusted_last_seen_event_id: trustedLastSeenEventId ?? lastSeenEventId,
210
+ // }),
211
+ // };
212
+ // }
213
+
214
+ /**
215
+ * Get user updates for DMs (polling for new messages)
216
+ * @param cursor - Cursor for pagination
217
+ * @param activeConversationId - ID of the currently active conversation
218
+ */
219
+ // public static userUpdates(cursor?: string, activeConversationId?: string): AxiosRequestConfig {
220
+ // return {
221
+ // method: 'get',
222
+ // url: 'https://x.com/i/api/1.1/dm/user_updates.json',
223
+ // params: {
224
+ // ...DM_BASE_PARAMS,
225
+ // /* eslint-disable @typescript-eslint/naming-convention */
226
+ // cursor: cursor,
227
+ // active_conversation_id: activeConversationId,
228
+ // dm_users: false,
229
+ // },
230
+ // paramsSerializer: { encode: encodeURIComponent },
231
+ // };
232
+ // }
233
+ }
@@ -6,6 +6,35 @@ import { AxiosRequestConfig } from 'axios';
6
6
  * @public
7
7
  */
8
8
  export class ListRequests {
9
+ /**
10
+ * @param listId - The ID of the target list.
11
+ * @param userId - The ID of the user to be added as a member.
12
+ */
13
+ public static addMember(listId: string, userId: string): AxiosRequestConfig {
14
+ return {
15
+ method: 'post',
16
+ url: 'https://x.com/i/api/graphql/uFQumgzNDR27zs0yK5J3Fw/ListAddMember',
17
+ data: {
18
+ /* eslint-disable @typescript-eslint/naming-convention */
19
+
20
+ variables: {
21
+ listId: listId,
22
+ userId: userId,
23
+ },
24
+ features: {
25
+ payments_enabled: false,
26
+ profile_label_improvements_pcf_label_in_post_enabled: false,
27
+ rweb_tipjar_consumption_enabled: false,
28
+ verified_phone_label_enabled: false,
29
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
30
+ responsive_web_graphql_timeline_navigation_enabled: false,
31
+ },
32
+
33
+ /* eslint-enable @typescript-eslint/naming-convention */
34
+ },
35
+ };
36
+ }
37
+
9
38
  /**
10
39
  * @param id - The id of the list whose details are to be fetched.
11
40
  */
@@ -83,6 +112,35 @@ export class ListRequests {
83
112
  };
84
113
  }
85
114
 
115
+ /**
116
+ * @param listId - The ID of the target list.
117
+ * @param userId - The ID of the user to remove as a member.
118
+ */
119
+ public static removeMember(listId: string, userId: string): AxiosRequestConfig {
120
+ return {
121
+ method: 'post',
122
+ url: 'https://x.com/i/api/graphql/IzgPnK3wZpNgpcN31ry3Xg/ListRemoveMember',
123
+ data: {
124
+ /* eslint-disable @typescript-eslint/naming-convention */
125
+
126
+ variables: {
127
+ listId: listId,
128
+ userId: userId,
129
+ },
130
+ features: {
131
+ payments_enabled: false,
132
+ profile_label_improvements_pcf_label_in_post_enabled: false,
133
+ rweb_tipjar_consumption_enabled: false,
134
+ verified_phone_label_enabled: false,
135
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
136
+ responsive_web_graphql_timeline_navigation_enabled: false,
137
+ },
138
+
139
+ /* eslint-enable @typescript-eslint/naming-convention */
140
+ },
141
+ };
142
+ }
143
+
86
144
  /**
87
145
  * @param id - The id of the list whose tweets are to be fetched.
88
146
  * @param count - The number of tweets to fetch. Must be \<= 100.
@@ -13,6 +13,21 @@ import { INewTweet } from '../types/args/PostArgs';
13
13
  * @public
14
14
  */
15
15
  export class TweetRequests {
16
+ /**
17
+ * @param id - The ID of the tweet to bookmark
18
+ */
19
+ public static bookmark(id: string): AxiosRequestConfig {
20
+ return {
21
+ method: 'post',
22
+ url: 'https://x.com/i/api/graphql/aoDbu3RHznuiSkQ9aNM67Q/CreateBookmark',
23
+ data: {
24
+ /* eslint-disable @typescript-eslint/naming-convention */
25
+ variables: JSON.stringify({ tweet_id: id }),
26
+ /* eslint-enable @typescript-eslint/naming-convention */
27
+ },
28
+ };
29
+ }
30
+
16
31
  /**
17
32
  * @param ids - The IDs of the tweets whose details are to be fetched.
18
33
  */
@@ -501,6 +516,23 @@ export class TweetRequests {
501
516
  };
502
517
  }
503
518
 
519
+ /**
520
+ * @param id - The id of the tweet to be unbookmarked.
521
+ */
522
+ public static unbookmark(id: string): AxiosRequestConfig {
523
+ return {
524
+ method: 'post',
525
+ url: 'https://x.com/i/api/graphql/Wlmlj2-xzyS1GN3a6cj-mQ/DeleteBookmark',
526
+ data: {
527
+ /* eslint-disable @typescript-eslint/naming-convention */
528
+ variables: {
529
+ tweet_id: id,
530
+ },
531
+ /* eslint-enable @typescript-eslint/naming-convention */
532
+ },
533
+ };
534
+ }
535
+
504
536
  /**
505
537
  * @param id - The id of the tweet to be unliked.
506
538
  */
@@ -73,23 +73,31 @@ export class UserRequests {
73
73
  * @param toTime - The end time of the analytic data to be fetched.
74
74
  * @param granularity - The granularity of the analytic data to be fetched.
75
75
  * @param requestedMetrics - The metrics to be fetched.
76
+ * @param showVerifiedFollowers - Whether to show verified followers in the analytics.
76
77
  */
77
78
  public static analytics(
78
79
  fromTime: Date,
79
80
  toTime: Date,
80
81
  granularity: RawAnalyticsGranularity,
81
82
  requestedMetrics: RawAnalyticsMetric[],
83
+ showVerifiedFollowers: boolean,
82
84
  ): AxiosRequestConfig {
85
+ console.log(
86
+ `Fetching analytics from ${fromTime?.toString()} to ${toTime?.toString()} with granularity ${granularity} and metrics ${requestedMetrics.join(', ')}`,
87
+ );
83
88
  return {
84
89
  method: 'get',
85
- url: 'https://x.com/i/api/graphql/NlJ6RM-hgHxt-iu9cPQz7A/overviewDataUserQuery',
90
+ url: 'https://x.com/i/api/graphql/LwtiA7urqM6eDeBheAFi5w/AccountOverviewQuery',
86
91
  params: {
87
- /* eslint-disable @typescript-eslint/naming-convention */
88
- from_time: fromTime,
89
- to_time: toTime,
90
- granularity: granularity,
91
- requested_metrics: requestedMetrics,
92
- /* eslint-enable @typescript-eslint/naming-convention */
92
+ variables: JSON.stringify({
93
+ /* eslint-disable @typescript-eslint/naming-convention */
94
+ from_time: fromTime,
95
+ to_time: toTime,
96
+ granularity: granularity,
97
+ requested_metrics: requestedMetrics,
98
+ show_verified_followers: showVerifiedFollowers,
99
+ /* eslint-enable @typescript-eslint/naming-convention */
100
+ }),
93
101
  },
94
102
  paramsSerializer: { encode: encodeURIComponent },
95
103
  };
@@ -539,6 +547,61 @@ export class UserRequests {
539
547
  };
540
548
  }
541
549
 
550
+ /**
551
+ * @param id - The id of the user whose lists are to be fetched.
552
+ * @param count - The number of lists to fetch. Only works as a lower limit when used with a cursor.
553
+ * @param cursor - The cursor to the batch of lists to fetch.
554
+ */
555
+ public static lists(id: string, count?: number, cursor?: string): AxiosRequestConfig {
556
+ return {
557
+ method: 'get',
558
+ url: 'https://x.com/i/api/graphql/tZg2CHWw-NAL0nKO2Q-P4Q/ListsManagementPageTimeline',
559
+ params: {
560
+ /* eslint-disable @typescript-eslint/naming-convention */
561
+ variables: JSON.stringify({ count: 100, cursor: cursor }),
562
+ features: JSON.stringify({
563
+ rweb_video_screen_enabled: false,
564
+ payments_enabled: false,
565
+ rweb_xchat_enabled: false,
566
+ profile_label_improvements_pcf_label_in_post_enabled: true,
567
+ rweb_tipjar_consumption_enabled: true,
568
+ verified_phone_label_enabled: true,
569
+ creator_subscriptions_tweet_preview_api_enabled: true,
570
+ responsive_web_graphql_timeline_navigation_enabled: true,
571
+ responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
572
+ premium_content_api_read_enabled: false,
573
+ communities_web_enable_tweet_community_results_fetch: true,
574
+ c9s_tweet_anatomy_moderator_badge_enabled: true,
575
+ responsive_web_grok_analyze_button_fetch_trends_enabled: false,
576
+ responsive_web_grok_analyze_post_followups_enabled: true,
577
+ responsive_web_jetfuel_frame: true,
578
+ responsive_web_grok_share_attachment_enabled: true,
579
+ articles_preview_enabled: true,
580
+ responsive_web_edit_tweet_api_enabled: true,
581
+ graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
582
+ view_counts_everywhere_api_enabled: true,
583
+ longform_notetweets_consumption_enabled: true,
584
+ responsive_web_twitter_article_tweet_consumption_enabled: true,
585
+ tweet_awards_web_tipping_enabled: false,
586
+ responsive_web_grok_show_grok_translated_post: false,
587
+ responsive_web_grok_analysis_button_from_backend: true,
588
+ creator_subscriptions_quote_tweet_preview_enabled: false,
589
+ freedom_of_speech_not_reach_fetch_enabled: true,
590
+ standardized_nudges_misinfo: true,
591
+ tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
592
+ longform_notetweets_rich_text_read_enabled: true,
593
+ longform_notetweets_inline_media_enabled: true,
594
+ responsive_web_grok_image_annotation_enabled: true,
595
+ responsive_web_grok_community_note_auto_translation_is_enabled: false,
596
+ responsive_web_enhance_cards_enabled: false,
597
+ }),
598
+ fieldToggles: { withArticlePlainText: false },
599
+ /* eslint-enable @typescript-eslint/naming-convention */
600
+ },
601
+ paramsSerializer: { encode: encodeURIComponent },
602
+ };
603
+ }
604
+
542
605
  /**
543
606
  * @param id - The id of the user whose media is to be fetched.
544
607
  * @param count - The number of media to fetch. Only works as a lower limit when used with a cursor.
@@ -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
+ }