emusks 0.0.3 → 2.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 (42) hide show
  1. package/README.md +4 -277
  2. package/build/graphql.js +24 -0
  3. package/build/v1.1.js +28 -0
  4. package/build/v2.js +28 -0
  5. package/package.json +16 -8
  6. package/src/clients.js +62 -0
  7. package/src/cycletls.js +26 -0
  8. package/src/flow.js +399 -0
  9. package/src/graphql.js +70 -0
  10. package/src/helpers/account.js +271 -0
  11. package/src/helpers/bookmarks.js +120 -0
  12. package/src/helpers/communities.js +271 -0
  13. package/src/helpers/dms.js +131 -0
  14. package/src/helpers/index.js +32 -0
  15. package/src/helpers/lists.js +229 -0
  16. package/src/helpers/media.js +274 -0
  17. package/src/helpers/notifications.js +49 -0
  18. package/src/helpers/search.js +129 -0
  19. package/src/helpers/spaces.js +55 -0
  20. package/src/helpers/syndication.js +33 -0
  21. package/src/helpers/timelines.js +84 -0
  22. package/src/helpers/topics.js +99 -0
  23. package/src/helpers/trends.js +86 -0
  24. package/src/helpers/tweets.js +403 -0
  25. package/src/helpers/users.js +321 -0
  26. package/src/index.js +125 -55
  27. package/src/parsers/timeline.js +105 -0
  28. package/src/static/graphql.js +1 -0
  29. package/src/static/v1.1.js +1 -0
  30. package/src/static/v2.js +1 -0
  31. package/src/v1.1.js +64 -0
  32. package/src/v2.js +64 -0
  33. package/src/methods/bookmarks.js +0 -91
  34. package/src/methods/follow.js +0 -88
  35. package/src/methods/like.js +0 -87
  36. package/src/methods/notifications.js +0 -121
  37. package/src/methods/retweet.js +0 -91
  38. package/src/methods/search.js +0 -124
  39. package/src/methods/timeline.js +0 -215
  40. package/src/methods/tweet.js +0 -396
  41. package/src/methods/users.js +0 -209
  42. package/src/utils/headers.js +0 -23
@@ -1,124 +0,0 @@
1
- import headers from "../utils/headers.js";
2
-
3
- export async function search(query, { resultsCount, product, cursor } = {}) {
4
- if (!this.auth.cookies) {
5
- throw new Error("you must be logged in to search");
6
- }
7
-
8
- const variables = {
9
- rawQuery: query,
10
- count: resultsCount || 20,
11
- querySource: "advanced_search_page",
12
- product: product || "Latest",
13
- includePromotedContent: false,
14
- };
15
-
16
- if (cursor) {
17
- variables.cursor = cursor;
18
- }
19
-
20
- const out = await (
21
- await fetch(
22
- `https://pro.x.com/i/api/graphql/EP_W_cLzULmRd5E_X-PJkA/SearchTimeline?variables=${encodeURIComponent(
23
- JSON.stringify(variables)
24
- )}&features=${encodeURIComponent(
25
- JSON.stringify({
26
- rweb_video_screen_enabled: false,
27
- payments_enabled: false,
28
- profile_label_improvements_pcf_label_in_post_enabled: true,
29
- rweb_tipjar_consumption_enabled: true,
30
- verified_phone_label_enabled: false,
31
- creator_subscriptions_tweet_preview_api_enabled: true,
32
- responsive_web_graphql_timeline_navigation_enabled: true,
33
- responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
34
- premium_content_api_read_enabled: false,
35
- communities_web_enable_tweet_community_results_fetch: true,
36
- c9s_tweet_anatomy_moderator_badge_enabled: true,
37
- responsive_web_grok_analyze_button_fetch_trends_enabled: false,
38
- responsive_web_grok_analyze_post_followups_enabled: true,
39
- responsive_web_jetfuel_frame: false,
40
- responsive_web_grok_share_attachment_enabled: true,
41
- articles_preview_enabled: true,
42
- responsive_web_edit_tweet_api_enabled: true,
43
- graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
44
- view_counts_everywhere_api_enabled: true,
45
- longform_notetweets_consumption_enabled: true,
46
- responsive_web_twitter_article_tweet_consumption_enabled: true,
47
- tweet_awards_web_tipping_enabled: false,
48
- responsive_web_grok_show_grok_translated_post: false,
49
- responsive_web_grok_analysis_button_from_backend: false,
50
- creator_subscriptions_quote_tweet_preview_enabled: false,
51
- freedom_of_speech_not_reach_fetch_enabled: true,
52
- standardized_nudges_misinfo: true,
53
- tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
54
- longform_notetweets_rich_text_read_enabled: true,
55
- longform_notetweets_inline_media_enabled: true,
56
- responsive_web_grok_image_annotation_enabled: true,
57
- responsive_web_enhance_cards_enabled: false,
58
- })
59
- )}`,
60
- {
61
- headers: {
62
- Accept: "*/*",
63
- "accept-language": "en-US,en;q=0.9",
64
-
65
- authorization:
66
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
67
-
68
- "content-type": "application/json",
69
-
70
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
71
- "x-csrf-token": this.auth.csrfToken,
72
-
73
- "x-twitter-active-user": "yes",
74
- "x-twitter-auth-type": "OAuth2Session",
75
- "x-twitter-client-language": "en",
76
-
77
- cookie: this.auth.cookies,
78
- ...headers,
79
- },
80
- }
81
- )
82
- ).json();
83
-
84
- if (
85
- !out?.data?.search_by_raw_query?.search_timeline?.timeline?.instructions
86
- ) {
87
- throw new Error(`failed to search: ${JSON.stringify(out, null, 2)}`);
88
- }
89
-
90
- const instructions =
91
- out.data.search_by_raw_query.search_timeline.timeline.instructions;
92
-
93
- // Find the TimelineAddEntries instruction
94
- const addEntriesInstruction = instructions.find(
95
- (instruction) => instruction.type === "TimelineAddEntries"
96
- );
97
-
98
- if (!addEntriesInstruction) {
99
- throw new Error("failed to find timeline entries in search response");
100
- }
101
-
102
- const entries = addEntriesInstruction.entries;
103
-
104
- // Extract cursors for pagination
105
- const cursors = {
106
- top: null,
107
- bottom: null,
108
- };
109
-
110
- entries.forEach((entry) => {
111
- if (entry.entryId && entry.entryId.startsWith("cursor-")) {
112
- if (entry.entryId.includes("top")) {
113
- cursors.top = entry.content?.value;
114
- } else if (entry.entryId.includes("bottom")) {
115
- cursors.bottom = entry.content?.value;
116
- }
117
- }
118
- });
119
-
120
- return {
121
- entries: entries.filter((entry) => !entry.entryId.startsWith("cursor-")),
122
- cursors,
123
- };
124
- }
@@ -1,215 +0,0 @@
1
- import headers from "../utils/headers.js";
2
- import parseTweet from "../parsers/tweet.js";
3
-
4
- export async function getTimeline({
5
- count = 20,
6
- cursor = undefined,
7
- includeAds = false,
8
- seenTweetIds = [],
9
- type = "foryou",
10
- } = {}) {
11
- if (!this.auth.cookies) {
12
- throw new Error("you must be logged in to get timeline");
13
- }
14
-
15
- if (!["foryou", "following"].includes(type)) {
16
- throw new Error("type must be either 'foryou' or 'following'");
17
- }
18
-
19
- const isFollowing = type === "following";
20
- const endpoint = isFollowing
21
- ? "https://pro.x.com/i/api/graphql/ewrSxRr-SMI1kW9gzg7JPg/HomeLatestTimeline"
22
- : "https://pro.x.com/i/api/graphql/Ri47TC1RogqkfaInTxucqA/HomeTimeline";
23
-
24
- const queryId = isFollowing
25
- ? "ewrSxRr-SMI1kW9gzg7JPg"
26
- : "Ri47TC1RogqkfaInTxucqA";
27
-
28
- const variables = {
29
- count,
30
- includePromotedContent: includeAds,
31
- latestControlAvailable: true,
32
- seenTweetIds,
33
- };
34
-
35
- if (isFollowing) {
36
- variables.requestContext = "launch";
37
- } else {
38
- variables.cursor = cursor;
39
- variables.withCommunity = true;
40
- }
41
-
42
- const features = {
43
- rweb_video_screen_enabled: false,
44
- payments_enabled: false,
45
- profile_label_improvements_pcf_label_in_post_enabled: true,
46
- rweb_tipjar_consumption_enabled: true,
47
- verified_phone_label_enabled: false,
48
- creator_subscriptions_tweet_preview_api_enabled: true,
49
- responsive_web_graphql_timeline_navigation_enabled: true,
50
- responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
51
- premium_content_api_read_enabled: false,
52
- communities_web_enable_tweet_community_results_fetch: true,
53
- c9s_tweet_anatomy_moderator_badge_enabled: true,
54
- responsive_web_grok_analyze_button_fetch_trends_enabled: false,
55
- responsive_web_grok_analyze_post_followups_enabled: true,
56
- responsive_web_jetfuel_frame: false,
57
- responsive_web_grok_share_attachment_enabled: true,
58
- articles_preview_enabled: true,
59
- responsive_web_edit_tweet_api_enabled: true,
60
- graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
61
- view_counts_everywhere_api_enabled: true,
62
- longform_notetweets_consumption_enabled: true,
63
- responsive_web_twitter_article_tweet_consumption_enabled: true,
64
- tweet_awards_web_tipping_enabled: false,
65
- responsive_web_grok_show_grok_translated_post: isFollowing ? false : true,
66
- responsive_web_grok_analysis_button_from_backend: isFollowing
67
- ? false
68
- : true,
69
- creator_subscriptions_quote_tweet_preview_enabled: false,
70
- freedom_of_speech_not_reach_fetch_enabled: true,
71
- standardized_nudges_misinfo: true,
72
- tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
73
- longform_notetweets_rich_text_read_enabled: true,
74
- longform_notetweets_inline_media_enabled: true,
75
- responsive_web_grok_image_annotation_enabled: true,
76
- responsive_web_enhance_cards_enabled: false,
77
- };
78
-
79
- try {
80
- const response = await fetch(endpoint, {
81
- headers: {
82
- accept: "*/*",
83
- "accept-language": "en-US,en;q=0.9",
84
- authorization:
85
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
86
- "content-type": "application/json",
87
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
88
- "x-csrf-token": this.auth.csrfToken,
89
- "x-twitter-active-user": "yes",
90
- "x-twitter-auth-type": "OAuth2Session",
91
- "x-twitter-client-language": "en",
92
- cookie: this.auth.cookies,
93
- ...headers,
94
- },
95
- body: JSON.stringify({
96
- variables,
97
- features,
98
- queryId,
99
- }),
100
- method: "POST",
101
- mode: "cors",
102
- credentials: "include",
103
- });
104
-
105
- if (!response.ok) {
106
- throw new Error(
107
- `Timeline request failed: ${response.status} ${response.statusText}`
108
- );
109
- }
110
-
111
- const data = await response.json();
112
- return parseTimelineResponse(data);
113
- } catch (error) {
114
- throw new Error(`Failed to fetch timeline: ${error.message}`);
115
- }
116
- }
117
-
118
- function parseTimelineResponse(data) {
119
- const result = {
120
- timeline: [],
121
- cursors: {
122
- top: null,
123
- bottom: null,
124
- },
125
- metadata: {
126
- scribeConfig: null,
127
- },
128
- };
129
-
130
- try {
131
- const instructions =
132
- data?.data?.home?.home_timeline_urt?.instructions || [];
133
-
134
- const addEntriesInstruction = instructions.find(
135
- (instruction) => instruction.type === "TimelineAddEntries"
136
- );
137
-
138
- if (addEntriesInstruction?.metadata?.scribeConfig) {
139
- result.metadata.scribeConfig =
140
- addEntriesInstruction.metadata.scribeConfig;
141
- }
142
-
143
- const entries = addEntriesInstruction?.entries || [];
144
-
145
- for (const entry of entries) {
146
- const { entryId, content } = entry;
147
-
148
- if (entryId.startsWith("tweet-")) {
149
- const tweetData = content?.itemContent?.tweet_results?.result;
150
- if (tweetData && tweetData.__typename === "Tweet") {
151
- const parsedTweet = parseTweet(tweetData);
152
- if (parsedTweet) {
153
- result.timeline.push({
154
- type: "tweet",
155
- data: parsedTweet,
156
- });
157
- }
158
- }
159
- } else if (entryId.startsWith("home-conversation-")) {
160
- const conversationData = content?.items || [];
161
- const conversation = {
162
- id: entryId.replace("home-conversation-", ""),
163
- tweets: [],
164
- };
165
-
166
- for (const item of conversationData) {
167
- const tweetData = item?.item?.itemContent?.tweet_results?.result;
168
- if (tweetData && tweetData.__typename === "Tweet") {
169
- const parsedTweet = parseTweet(tweetData);
170
- if (parsedTweet) {
171
- conversation.tweets.push(parsedTweet);
172
- }
173
- }
174
- }
175
-
176
- if (conversation.tweets.length > 0) {
177
- result.timeline.push({
178
- type: "conversation",
179
- data: conversation,
180
- });
181
- }
182
- } else if (entryId.startsWith("who-to-follow-")) {
183
- const userItems = content?.items || [];
184
- const users = [];
185
- for (const item of userItems) {
186
- const userData = item?.item?.itemContent?.user_results?.result;
187
- if (userData && userData.__typename === "User") {
188
- users.push(userData);
189
- }
190
- }
191
-
192
- if (users.length > 0) {
193
- result.timeline.push({
194
- type: "suggested_users",
195
- data: {
196
- id: entryId.replace("who-to-follow-", ""),
197
- users: users,
198
- },
199
- });
200
- }
201
- } else if (entryId.startsWith("cursor-")) {
202
- const cursorValue = content?.value;
203
- if (entryId.includes("top")) {
204
- result.cursors.top = cursorValue;
205
- } else if (entryId.includes("bottom")) {
206
- result.cursors.bottom = cursorValue;
207
- }
208
- }
209
- }
210
-
211
- return result;
212
- } catch (error) {
213
- throw new Error(`Failed to parse timeline response: ${error.message}`);
214
- }
215
- }