emusks 0.0.2 → 2.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 (43) 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 +290 -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 +405 -0
  25. package/src/helpers/users.js +321 -0
  26. package/src/index.js +125 -55
  27. package/src/parsers/timeline.js +141 -0
  28. package/src/parsers/tweet.js +9 -2
  29. package/src/static/graphql.js +1 -0
  30. package/src/static/v1.1.js +1 -0
  31. package/src/static/v2.js +1 -0
  32. package/src/v1.1.js +64 -0
  33. package/src/v2.js +64 -0
  34. package/src/methods/bookmarks.js +0 -91
  35. package/src/methods/follow.js +0 -88
  36. package/src/methods/like.js +0 -87
  37. package/src/methods/notifications.js +0 -121
  38. package/src/methods/retweet.js +0 -91
  39. package/src/methods/search.js +0 -124
  40. package/src/methods/timeline.js +0 -215
  41. package/src/methods/tweet.js +0 -396
  42. package/src/methods/users.js +0 -209
  43. package/src/utils/headers.js +0 -23
@@ -0,0 +1 @@
1
+ export default {"account/multi/list":["get","https://api.x.com/1.1/account/multi/list.json"],"onboarding/sso_init":["post","https://api.x.com/1.1/onboarding/sso_init.json"],"account/logout":["post","https://api.x.com/1.1/account/logout.json"],"account/multi/clean":["post","https://api.x.com/1.1/account/multi/clean.json"],"account/multi/add":["post","https://api.x.com/1.1/account/multi/add.json"],"account/multi/switch":["post","https://api.x.com/1.1/account/multi/switch.json"],"account/multi/logout_all":["post","https://api.x.com/1.1/account/multi/logout_all.json"],"dm/welcome_messages/add_to_conversation":["post","https://api.x.com/1.1/dm/welcome_messages/add_to_conversation.json"],"dm/conversation/bulk_delete":["post","https://api.x.com/1.1/dm/conversation/bulk_delete.json"],"dm/edit":["post","https://api.x.com/1.1/dm/edit.json"],"dm/conversation":["get","https://api.x.com/1.1/dm/conversation.json"],"dm/inbox_initial_state":["get","https://api.x.com/1.1/dm/inbox_initial_state.json"],"dm/user_updates":["get","https://api.x.com/1.1/dm/user_updates.json"],"dm/search/query":["post","https://api.x.com/1.1/dm/search/query.json"],"dm/user/update_relationship_state":["post","https://api.x.com/1.1/dm/user/update_relationship_state.json"],"dm/permissions":["get","https://api.x.com/1.1/dm/permissions.json"],"dm/permissions/secret":["get","https://api.x.com/1.1/dm/permissions/secret.json"],"direct_messages/report_spam":["post","https://api.x.com/1.1/direct_messages/report_spam.json"],"dm/report":["post","https://api.x.com/1.1/dm/report.json"],"dm/update_last_seen_event_id":["post","https://api.x.com/1.1/dm/update_last_seen_event_id.json"],"friendships/incoming":["get","https://api.x.com/1.1/friendships/incoming.json"],"friends/list":["get","https://api.x.com/1.1/friends/list.json"],"friends/following/list":["get","https://api.x.com/1.1/friends/following/list.json"],"friendships/accept":["post","https://api.x.com/1.1/friendships/accept.json"],"friendships/deny":["post","https://api.x.com/1.1/friendships/deny.json"],"friendships/update":["post","https://api.x.com/1.1/friendships/update.json"],"friendships/create_all":["post","https://api.x.com/1.1/friendships/create_all.json"],"friendships/destroy_all":["post","https://api.x.com/1.1/friendships/destroy_all.json"],"jot/external_referer":["post","https://api.x.com/1.1/jot/external_referer.json"],"lists/memberships":["get","https://api.x.com/1.1/lists/memberships.json"],"onboarding/task":["post","https://api.x.com/1.1/onboarding/task.json"],"onboarding/contacts_authorize":["post","https://api.x.com/1.1/onboarding/contacts_authorize.json"],"onboarding/contacts_import_status":["get","https://api.x.com/1.1/onboarding/contacts_import_status.json"],"onboarding/verification_status":["get","https://api.x.com/1.1/onboarding/verification_status.json"],"onboarding/referrer":["post","https://api.x.com/1.1/onboarding/referrer.json"],"contacts/destroy/all":["post","https://api.x.com/1.1/contacts/destroy/all.json"],"onboarding/begin_verification":["post","https://api.x.com/1.1/onboarding/begin_verification.json"],"onboarding/verify":["post","https://api.x.com/1.1/onboarding/verify.json"],"onboarding/fetch_user_recommendations":["post","https://api.x.com/1.1/onboarding/fetch_user_recommendations.json"],"promoted_content/log":["post","https://api.x.com/1.1/promoted_content/log.json"],"get:account/settings":["get","https://api.x.com/1.1/account/settings.json"],"post:account/settings":["post","https://api.x.com/1.1/account/settings.json"],"sso/delete_connection":["post","https://api.x.com/1.1/sso/delete_connection.json"],"account/remove_profile_banner":["post","https://api.x.com/1.1/account/remove_profile_banner.json"],"account/update_profile_image":["post","https://api.x.com/1.1/account/update_profile_image.json"],"account/update_profile_banner":["post","https://api.x.com/1.1/account/update_profile_banner.json"],"account/deactivate":["post","https://api.x.com/1.1/account/deactivate.json"],"account/verify_password":["post","https://api.x.com/1.1/account/verify_password.json"],"application/rate_limit_status":["get","https://api.x.com/1.1/application/rate_limit_status.json"],"hashflags":["get","https://api.x.com/1.1/hashflags.json"],"geo/delete_location_data":["post","https://api.x.com/1.1/geo/delete_location_data.json"],"get:mutes/advanced_filters":["get","https://api.x.com/1.1/mutes/advanced_filters.json"],"post:mutes/advanced_filters":["post","https://api.x.com/1.1/mutes/advanced_filters.json"],"account/update_profile":["post","https://api.x.com/1.1/account/update_profile.json"],"oauth/list":["get","https://api.x.com/1.1/oauth/list.json"],"oauth/revoke":["post","https://api.x.com/1.1/oauth/revoke.json"],"account/change_password":["post","https://x.com/i/api/1.1/account/change_password.json"],"trends/available":["get","https://api.x.com/1.1/trends/available.json"],"get:account/backup_code":["get","https://api.x.com/1.1/account/backup_code.json"],"post:account/backup_code":["post","https://api.x.com/1.1/account/backup_code.json"],"account/login_verification/temporary_password":["post","https://api.x.com/1.1/account/login_verification/temporary_password.json"],"account/login_verification_enrollment":["delete","https://api.x.com/1.1/account/login_verification_enrollment.json"],"account/login_verification/remove_method":["post","https://api.x.com/1.1/account/login_verification/remove_method.json"],"account/login_verification/rename_security_key_method":["post","https://api.x.com/1.1/account/login_verification/rename_security_key_method.json"],"search/typeahead":["get","https://api.x.com/1.1/search/typeahead.json"],"friendships/create":["post","https://api.x.com/1.1/friendships/create.json"],"friendships/destroy":["post","https://api.x.com/1.1/friendships/destroy.json"],"friendships/cancel":["post","https://api.x.com/1.1/friendships/cancel.json"],"blocks/create":["post","https://api.x.com/1.1/blocks/create.json"],"blocks/destroy":["post","https://api.x.com/1.1/blocks/destroy.json"],"mutes/users/create":["post","https://api.x.com/1.1/mutes/users/create.json"],"mutes/users/destroy":["post","https://api.x.com/1.1/mutes/users/destroy.json"],"users/lookup":["get","https://api.x.com/1.1/users/lookup.json"],"users/email_phone_info":["get","https://api.x.com/1.1/users/email_phone_info.json"],"account/resend_confirmation_email":["post","https://api.x.com/1.1/account/resend_confirmation_email.json"],"device/unregister":["post","https://api.x.com/1.1/device/unregister.json"],"notifications/settings/save":["post","https://api.x.com/1.1/notifications/settings/save.json"],"notifications/settings/login":["post","https://api.x.com/1.1/notifications/settings/login.json"],"notifications/settings/checkin":["post","https://api.x.com/1.1/notifications/settings/checkin.json"],"notifications/settings/logout":["post","https://api.x.com/1.1/notifications/settings/logout.json"],"help/settings":["get","https://api.x.com/1.1/help/settings.json"],"media/metadata/create":["post","https://api.x.com/1.1/media/metadata/create.json"],"media/subtitles/create":["post","https://api.x.com/1.1/media/subtitles/create.json"],"account/personalization/twitter_interests":["get","https://api.x.com/1.1/account/personalization/twitter_interests.json"],"account/personalization/email_your_data":["post","https://api.x.com/1.1/account/personalization/email_your_data.json"],"account/personalization/set_optout_cookies":["get","https://api.x.com/1.1/account/personalization/set_optout_cookies.json"],"live_pipeline/update_subscriptions":["post","https://api.x.com/1.1/live_pipeline/update_subscriptions.json"],"geo/places":["get","https://api.x.com/1.1/geo/places.json"],"users/recommendations":["get","https://api.x.com/1.1/users/recommendations.json"],"saved_searches/list":["get","https://api.x.com/1.1/saved_searches/list.json"],"saved_searches/create":["post","https://api.x.com/1.1/saved_searches/create.json"],"keyregistry/register":["post","https://api.x.com/1.1/keyregistry/register.json"],"account/not_my_account/disassociate":["post","https://api.x.com/1.1/account/not_my_account/disassociate.json"],"account/not_my_account/get_masked_data":["get","https://api.x.com/1.1/account/not_my_account/get_masked_data.json"],"collections/entries":["get","https://api.x.com/1.1/collections/entries.json"],"foundmedia/categories":["get","https://api.x.com/1.1/foundmedia/categories.json"],"foundmedia/search":["get","https://api.x.com/1.1/foundmedia/search.json"],"get:account/user_twitter_data":["get","https://api.x.com/1.1/account/user_twitter_data.json"],"put:account/user_twitter_data":["put","https://api.x.com/1.1/account/user_twitter_data.json"],"contacts/addressbook":["get","https://api.x.com/1.1/contacts/addressbook.json"],"mutes/keywords/list":["get","https://api.x.com/1.1/mutes/keywords/list.json"],"mutes/keywords/destroy":["post","https://api.x.com/1.1/mutes/keywords/destroy.json"],"mutes/keywords/update":["post","https://api.x.com/1.1/mutes/keywords/update.json"],"onboarding/bounce":["post","https://api.x.com/1.1/onboarding/bounce.json"],"report/flow":["post","https://api.x.com/1.1/report/flow.json"],"account/password_strength":["post","https://api.x.com/1.1/account/password_strength.json"],"users/phone_number_available":["get","https://api.x.com/1.1/users/phone_number_available.json"],"users/email_available":["get","https://x.com/i/api/1.1/users/email_available.json"],"moments/create":["post","https://api.x.com/1.1/moments/create.json"]};
@@ -0,0 +1 @@
1
+ export default {"badge_count/badge_count":["get","https://x.com/i/api/2/badge_count/badge_count.json"],"guide/get_explore_settings":["get","https://x.com/i/api/2/guide/get_explore_settings.json"],"guide/set_explore_settings":["post","https://x.com/i/api/2/guide/set_explore_settings.json"],"guide/explore_locations_with_auto_complete":["get","https://x.com/i/api/2/guide/explore_locations_with_auto_complete.json"],"timeline/reactive":["get","https://x.com/i/api/2/timeline/reactive.json"],"moments/list_user_moments":["get","https://x.com/i/api/2/moments/list_user_moments.json"],"guide":["get","https://x.com/i/api/2/guide.json"],"guide/topic":["get","https://x.com/i/api/2/guide/topic.json"],"onboarding/fetch_user_recommendations_urt":["get","https://x.com/i/api/2/onboarding/fetch_user_recommendations_urt.json"],"people_discovery/modules_urt":["get","https://x.com/i/api/2/people_discovery/modules_urt.json"],"search/adaptive":["get","https://x.com/i/api/2/search/adaptive.json"],"timeline/fixture":["get","https://x.com/i/api/2/timeline/fixture.json"]};
package/src/v1.1.js ADDED
@@ -0,0 +1,64 @@
1
+ import getCycleTLS from "./cycletls.js";
2
+ import v1_1Api from "./static/v1.1.js";
3
+
4
+ export default async function v1_1(queryName, { params, body, headers } = {}) {
5
+ let entry = v1_1Api[queryName];
6
+ if (!entry) {
7
+ throw new Error(`v1.1 endpoint ${queryName} not found`);
8
+ }
9
+
10
+ const [method, baseUrl] = entry;
11
+
12
+ let finalUrl = baseUrl;
13
+
14
+ if (params && Object.keys(params).length) {
15
+ const searchParams = new URLSearchParams(params);
16
+ const separator = baseUrl.includes("?") ? "&" : "?";
17
+ finalUrl = `${baseUrl}${separator}${searchParams.toString()}`;
18
+ }
19
+
20
+ const url = new URL(finalUrl);
21
+ const pathname = url.pathname;
22
+
23
+ const requestHeaders = {
24
+ accept: "*/*",
25
+ "accept-language": "en-US,en;q=0.9",
26
+ authorization: `Bearer ${this.auth.client.bearer}`,
27
+ "content-type": "application/json",
28
+ "x-csrf-token": this.auth.csrfToken,
29
+ "x-twitter-active-user": "yes",
30
+ "x-twitter-auth-type": "OAuth2Session",
31
+ "x-twitter-client-language": "en",
32
+ "x-client-transaction-id": await this.auth.generateTransactionId(
33
+ method.toUpperCase(),
34
+ pathname,
35
+ ),
36
+ priority: "u=1, i",
37
+ "sec-ch-ua": '"Not(A:Brand";v="8", "Chromium";v="144"',
38
+ "sec-ch-ua-mobile": "?0",
39
+ "sec-ch-ua-platform": '"macOS"',
40
+ "sec-fetch-dest": "empty",
41
+ "sec-fetch-mode": "cors",
42
+ "sec-fetch-site": "same-origin",
43
+ "sec-gpc": "1",
44
+ cookie:
45
+ this.auth.client.headers.cookie + (this.elevatedCookies ? `; ${this.elevatedCookies}` : ""),
46
+ ...headers,
47
+ };
48
+
49
+ const cycleTLS = await getCycleTLS();
50
+
51
+ return await cycleTLS(
52
+ finalUrl,
53
+ {
54
+ headers: requestHeaders,
55
+ userAgent: this.auth.client.fingerprints.userAgent,
56
+ ja3: this.auth.client.fingerprints.ja3,
57
+ ja4r: this.auth.client.fingerprints.ja4r,
58
+ body: body || undefined,
59
+ proxy: this.proxy || undefined,
60
+ referrer: "https://x.com/",
61
+ },
62
+ method,
63
+ );
64
+ }
package/src/v2.js ADDED
@@ -0,0 +1,64 @@
1
+ import getCycleTLS from "./cycletls.js";
2
+ import v2Api from "./static/v2.js";
3
+
4
+ export default async function v2(queryName, { params, body, headers } = {}) {
5
+ let entry = v2Api[queryName];
6
+ if (!entry) {
7
+ throw new Error(`v2 endpoint ${queryName} not found`);
8
+ }
9
+
10
+ const [method, baseUrl] = entry;
11
+
12
+ let finalUrl = baseUrl;
13
+
14
+ if (params && Object.keys(params).length) {
15
+ const searchParams = new URLSearchParams(params);
16
+ const separator = baseUrl.includes("?") ? "&" : "?";
17
+ finalUrl = `${baseUrl}${separator}${searchParams.toString()}`;
18
+ }
19
+
20
+ const url = new URL(finalUrl);
21
+ const pathname = url.pathname;
22
+
23
+ const requestHeaders = {
24
+ accept: "*/*",
25
+ "accept-language": "en-US,en;q=0.9",
26
+ authorization: `Bearer ${this.auth.client.bearer}`,
27
+ "content-type": "application/json",
28
+ "x-csrf-token": this.auth.csrfToken,
29
+ "x-twitter-active-user": "yes",
30
+ "x-twitter-auth-type": "OAuth2Session",
31
+ "x-twitter-client-language": "en",
32
+ "x-client-transaction-id": await this.auth.generateTransactionId(
33
+ method.toUpperCase(),
34
+ pathname,
35
+ ),
36
+ priority: "u=1, i",
37
+ "sec-ch-ua": '"Not(A:Brand";v="8", "Chromium";v="144"',
38
+ "sec-ch-ua-mobile": "?0",
39
+ "sec-ch-ua-platform": '"macOS"',
40
+ "sec-fetch-dest": "empty",
41
+ "sec-fetch-mode": "cors",
42
+ "sec-fetch-site": "same-origin",
43
+ "sec-gpc": "1",
44
+ cookie:
45
+ this.auth.client.headers.cookie + (this.elevatedCookies ? `; ${this.elevatedCookies}` : ""),
46
+ ...headers,
47
+ };
48
+
49
+ const cycleTLS = await getCycleTLS();
50
+
51
+ return await cycleTLS(
52
+ finalUrl,
53
+ {
54
+ headers: requestHeaders,
55
+ userAgent: this.auth.client.fingerprints.userAgent,
56
+ ja3: this.auth.client.fingerprints.ja3,
57
+ ja4r: this.auth.client.fingerprints.ja4r,
58
+ body: body || undefined,
59
+ proxy: this.proxy || undefined,
60
+ referrer: "https://x.com/",
61
+ },
62
+ method,
63
+ );
64
+ }
@@ -1,91 +0,0 @@
1
- import headers from "../utils/headers.js";
2
-
3
- export async function bookmark(tweetId) {
4
- if (!this.auth.cookies) {
5
- throw new Error("you must be logged in to bookmark a tweet");
6
- }
7
-
8
- const out = await (
9
- await fetch(
10
- "https://pro.x.com/i/api/graphql/aoDbu3RHznuiSkQ9aNM67Q/CreateBookmark",
11
- {
12
- headers: {
13
- Accept: "*/*",
14
- "accept-language": "en-US,en;q=0.9",
15
-
16
- authorization:
17
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
18
- "content-type": "application/json",
19
-
20
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
21
- "x-csrf-token": this.auth.csrfToken,
22
-
23
- "x-twitter-active-user": "yes",
24
- "x-twitter-auth-type": "OAuth2Session",
25
- "x-twitter-client-language": "en",
26
-
27
- cookie: this.auth.cookies,
28
- ...headers,
29
- },
30
- body: JSON.stringify({
31
- variables: { tweet_id: tweetId },
32
- queryId: "aoDbu3RHznuiSkQ9aNM67Q",
33
- }),
34
- method: "POST",
35
- }
36
- )
37
- ).json();
38
-
39
- if (!out?.data?.tweet_bookmark_put) {
40
- throw new Error(
41
- `failed to bookmark tweet: ${JSON.stringify(out, null, 2)}`
42
- );
43
- }
44
-
45
- return true;
46
- }
47
-
48
- export async function unbookmark(tweetId) {
49
- if (!this.auth.cookies) {
50
- throw new Error("you must be logged in to unbookmark a tweet");
51
- }
52
-
53
- const out = await (
54
- await fetch(
55
- "https://pro.x.com/i/api/graphql/Wlmlj2-xzyS1GN3a6cj-mQ/DeleteBookmark",
56
- {
57
- headers: {
58
- Accept: "*/*",
59
- "accept-language": "en-US,en;q=0.9",
60
-
61
- authorization:
62
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
63
- "content-type": "application/json",
64
-
65
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
66
- "x-csrf-token": this.auth.csrfToken,
67
-
68
- "x-twitter-active-user": "yes",
69
- "x-twitter-auth-type": "OAuth2Session",
70
- "x-twitter-client-language": "en",
71
-
72
- cookie: this.auth.cookies,
73
- ...headers,
74
- },
75
- body: JSON.stringify({
76
- variables: { tweet_id: tweetId },
77
- queryId: "Wlmlj2-xzyS1GN3a6cj-mQ",
78
- }),
79
- method: "POST",
80
- }
81
- )
82
- ).json();
83
-
84
- if (!out?.data?.tweet_bookmark_delete) {
85
- throw new Error(
86
- `failed to unbookmark tweet: ${JSON.stringify(out, null, 2)}`
87
- );
88
- }
89
-
90
- return true;
91
- }
@@ -1,88 +0,0 @@
1
- import parseUser from "../parsers/user.js";
2
- import headers from "../utils/headers.js";
3
-
4
- export async function follow(userId) {
5
- if (!this.auth.cookies) {
6
- throw new Error("you must be logged in to follow someone");
7
- }
8
-
9
- const out = await (
10
- await fetch("https://pro.x.com/i/api/1.1/friendships/create.json", {
11
- headers: {
12
- Accept: "*/*",
13
- "accept-language": "en-US,en;q=0.9",
14
-
15
- authorization:
16
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
17
- "content-type": "application/x-www-form-urlencoded",
18
-
19
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
20
- "x-csrf-token": this.auth.csrfToken,
21
-
22
- "x-twitter-active-user": "yes",
23
- "x-twitter-auth-type": "OAuth2Session",
24
- "x-twitter-client-language": "en",
25
-
26
- cookie: this.auth.cookies,
27
- ...headers,
28
- },
29
-
30
- // i'm too lazy to make form data manually and this works
31
- // well so i'm just gonna use that
32
- body: `include_profile_interstitial_type=1&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&include_ext_is_blue_verified=1&include_ext_verified_type=1&include_ext_profile_image_shape=1&skip_status=1&user_id=${encodeURIComponent(
33
- userId
34
- )}`,
35
- method: "POST",
36
- })
37
- ).json();
38
-
39
- if (!out?.id) {
40
- throw new Error(`failed to follow user: ${JSON.stringify(out, null, 2)}`);
41
- }
42
-
43
- return {
44
- user: parseUser(out),
45
- };
46
- }
47
-
48
- export async function unfollow(userId) {
49
- if (!this.auth.cookies) {
50
- throw new Error("you must be logged in to follow someone");
51
- }
52
-
53
- const out = await (
54
- await fetch("https://pro.x.com/i/api/1.1/friendships/destroy.json", {
55
- headers: {
56
- Accept: "*/*",
57
- "accept-language": "en-US,en;q=0.9",
58
-
59
- authorization:
60
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
61
- "content-type": "application/x-www-form-urlencoded",
62
-
63
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
64
- "x-csrf-token": this.auth.csrfToken,
65
-
66
- "x-twitter-active-user": "yes",
67
- "x-twitter-auth-type": "OAuth2Session",
68
- "x-twitter-client-language": "en",
69
-
70
- cookie: this.auth.cookies,
71
- ...headers,
72
- },
73
-
74
- body: `include_profile_interstitial_type=1&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&include_ext_is_blue_verified=1&include_ext_verified_type=1&include_ext_profile_image_shape=1&skip_status=1&user_id=${encodeURIComponent(
75
- userId
76
- )}`,
77
- method: "POST",
78
- })
79
- ).json();
80
-
81
- if (!out?.id) {
82
- throw new Error(`failed to unfollow user: ${JSON.stringify(out, null, 2)}`);
83
- }
84
-
85
- return {
86
- user: parseUser(out),
87
- };
88
- }
@@ -1,87 +0,0 @@
1
- import headers from "../utils/headers.js";
2
-
3
- export async function like(tweetId) {
4
- if (!this.auth.cookies) {
5
- throw new Error("you must be logged in to like a tweet");
6
- }
7
-
8
- const out = await (
9
- await fetch(
10
- "https://pro.x.com/i/api/graphql/lI07N6Otwv1PhnEgXILM7A/FavoriteTweet",
11
- {
12
- headers: {
13
- Accept: "*/*",
14
- "accept-language": "en-US,en;q=0.9",
15
-
16
- authorization:
17
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
18
- "content-type": "application/json",
19
-
20
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
21
- "x-csrf-token": this.auth.csrfToken,
22
-
23
- "x-twitter-active-user": "yes",
24
- "x-twitter-auth-type": "OAuth2Session",
25
- "x-twitter-client-language": "en",
26
-
27
- cookie: this.auth.cookies,
28
- ...headers,
29
- },
30
- body: JSON.stringify({
31
- variables: { tweet_id: tweetId },
32
- queryId: "lI07N6Otwv1PhnEgXILM7A",
33
- }),
34
- method: "POST",
35
- }
36
- )
37
- ).json();
38
-
39
- if (!out?.data?.favorite_tweet) {
40
- throw new Error(`failed to like tweet: ${JSON.stringify(out, null, 2)}`);
41
- }
42
-
43
- return true;
44
- }
45
-
46
- export async function dislike(tweetId) {
47
- if (!this.auth.cookies) {
48
- throw new Error("you must be logged in to dislike a tweet");
49
- }
50
-
51
- const out = await (
52
- await fetch(
53
- "https://pro.x.com/i/api/graphql/ZYKSe-w7KEslx3JhSIk5LA/UnfavoriteTweet",
54
- {
55
- headers: {
56
- Accept: "*/*",
57
- "accept-language": "en-US,en;q=0.9",
58
-
59
- authorization:
60
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
61
- "content-type": "application/json",
62
-
63
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
64
- "x-csrf-token": this.auth.csrfToken,
65
-
66
- "x-twitter-active-user": "yes",
67
- "x-twitter-auth-type": "OAuth2Session",
68
- "x-twitter-client-language": "en",
69
-
70
- cookie: this.auth.cookies,
71
- ...headers,
72
- },
73
- body: JSON.stringify({
74
- variables: { tweet_id: tweetId },
75
- queryId: "ZYKSe-w7KEslx3JhSIk5LA",
76
- }),
77
- method: "POST",
78
- }
79
- )
80
- ).json();
81
-
82
- if (!out?.data?.unfavorite_tweet) {
83
- throw new Error(`failed to dislike tweet: ${JSON.stringify(out, null, 2)}`);
84
- }
85
-
86
- return true;
87
- }
@@ -1,121 +0,0 @@
1
- import headers from "../utils/headers.js";
2
-
3
- export async function getNotifications(
4
- { type = "All", limit = 20, cursor = undefined } = {
5
- type: "All",
6
- limit: 20,
7
- cursor: undefined,
8
- }
9
- ) {
10
- if (!this.auth.cookies) {
11
- throw new Error("you must be logged in to get notifications");
12
- }
13
-
14
- const variables = { timeline_type: type, count: limit };
15
- if (cursor) {
16
- variables.cursor = cursor;
17
- }
18
-
19
- const response = await (
20
- await fetch(
21
- `https://pro.x.com/i/api/graphql/WERRji0vXRGrMiQ8LPZ3sw/NotificationsTimeline?variables=${encodeURIComponent(
22
- JSON.stringify(variables)
23
- )}&features=${encodeURIComponent(
24
- JSON.stringify({
25
- rweb_video_screen_enabled: false,
26
- profile_label_improvements_pcf_label_in_post_enabled: true,
27
- rweb_tipjar_consumption_enabled: true,
28
- responsive_web_graphql_exclude_directive_enabled: true,
29
- verified_phone_label_enabled: false,
30
- creator_subscriptions_tweet_preview_api_enabled: true,
31
- responsive_web_graphql_timeline_navigation_enabled: true,
32
- responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
33
- premium_content_api_read_enabled: false,
34
- communities_web_enable_tweet_community_results_fetch: true,
35
- c9s_tweet_anatomy_moderator_badge_enabled: true,
36
- responsive_web_grok_analyze_button_fetch_trends_enabled: false,
37
- responsive_web_grok_analyze_post_followups_enabled: true,
38
- responsive_web_jetfuel_frame: false,
39
- responsive_web_grok_share_attachment_enabled: true,
40
- articles_preview_enabled: true,
41
- responsive_web_edit_tweet_api_enabled: true,
42
- graphql_is_translatable_rweb_tweet_is_translatable_enabled: true,
43
- view_counts_everywhere_api_enabled: true,
44
- longform_notetweets_consumption_enabled: true,
45
- responsive_web_twitter_article_tweet_consumption_enabled: true,
46
- tweet_awards_web_tipping_enabled: false,
47
- responsive_web_grok_show_grok_translated_post: false,
48
- responsive_web_grok_analysis_button_from_backend: false,
49
- creator_subscriptions_quote_tweet_preview_enabled: false,
50
- freedom_of_speech_not_reach_fetch_enabled: true,
51
- standardized_nudges_misinfo: true,
52
- tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled: true,
53
- longform_notetweets_rich_text_read_enabled: true,
54
- longform_notetweets_inline_media_enabled: true,
55
- responsive_web_grok_image_annotation_enabled: true,
56
- responsive_web_enhance_cards_enabled: false,
57
- })
58
- )}`,
59
- {
60
- headers: {
61
- Accept: "*/*",
62
- authorization:
63
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
64
- "content-type": "application/json",
65
- "x-csrf-token": this.auth.csrfToken,
66
- "x-twitter-active-user": "yes",
67
- "x-twitter-auth-type": "OAuth2Session",
68
- "x-twitter-client-language": "en",
69
- cookie: this.auth.cookies,
70
- ...headers,
71
- },
72
- }
73
- )
74
- ).json();
75
-
76
- if (
77
- !response?.data?.viewer_v2?.user_results?.result?.notification_timeline
78
- ?.timeline?.instructions
79
- ) {
80
- throw new Error(
81
- `failed to get notifications: ${JSON.stringify(response, null, 2)}`
82
- );
83
- }
84
-
85
- const instructions =
86
- response.data.viewer_v2.user_results.result.notification_timeline.timeline
87
- .instructions;
88
-
89
- const addEntriesInstruction = instructions.find(
90
- (instruction) => instruction.type === "TimelineAddEntries"
91
- );
92
-
93
- if (!addEntriesInstruction) {
94
- throw new Error(
95
- "failed to find timeline entries in notifications response"
96
- );
97
- }
98
-
99
- const entries = addEntriesInstruction.entries;
100
-
101
- // Extract cursors for pagination
102
- const cursors = {
103
- top: null,
104
- bottom: null,
105
- };
106
-
107
- entries.forEach((entry) => {
108
- if (entry.entryId.startsWith("cursor-")) {
109
- if (entry.entryId.includes("top")) {
110
- cursors.top = entry.content?.value;
111
- } else if (entry.entryId.includes("bottom")) {
112
- cursors.bottom = entry.content?.value;
113
- }
114
- }
115
- });
116
-
117
- return {
118
- entries: entries.filter((entry) => !entry.entryId.startsWith("cursor-")),
119
- cursors,
120
- };
121
- }
@@ -1,91 +0,0 @@
1
- import headers from "../utils/headers.js";
2
-
3
- export async function retweet(tweetId) {
4
- if (!this.auth.cookies) {
5
- throw new Error("you must be logged in to retweet");
6
- }
7
-
8
- const out = await (
9
- await fetch(
10
- "https://pro.x.com/i/api/graphql/ojPdsZsimiJrUGLR1sjUtA/CreateRetweet",
11
- {
12
- headers: {
13
- Accept: "*/*",
14
- "accept-language": "en-US,en;q=0.9",
15
-
16
- authorization:
17
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
18
- "content-type": "application/json",
19
-
20
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
21
- "x-csrf-token": this.auth.csrfToken,
22
-
23
- "x-twitter-active-user": "yes",
24
- "x-twitter-auth-type": "OAuth2Session",
25
- "x-twitter-client-language": "en",
26
-
27
- cookie: this.auth.cookies,
28
- ...headers,
29
- },
30
- body: JSON.stringify({
31
- variables: { tweet_id: tweetId, dark_request: false },
32
- queryId: "ojPdsZsimiJrUGLR1sjUtA",
33
- }),
34
- method: "POST",
35
- }
36
- )
37
- ).json();
38
-
39
- if (!out?.data?.create_retweet) {
40
- throw new Error(`failed to retweet: ${JSON.stringify(out, null, 2)}`);
41
- }
42
-
43
- return {
44
- post_id: out?.data?.create_retweet?.retweet_results?.result?.rest_id,
45
- post_url: `https://x.com/i/status/${out?.data?.create_retweet?.retweet_results?.result?.rest_id}`,
46
- response: out,
47
- };
48
- }
49
-
50
- export async function unretweet(tweetId) {
51
- if (!this.auth.cookies) {
52
- throw new Error("you must be logged in to undo a retweet");
53
- }
54
-
55
- const out = await (
56
- await fetch(
57
- "https://pro.x.com/i/api/graphql/iQtK4dl5hBmXewYZuEOKVw/DeleteRetweet",
58
- {
59
- headers: {
60
- Accept: "*/*",
61
- "accept-language": "en-US,en;q=0.9",
62
-
63
- authorization:
64
- "Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF",
65
- "content-type": "application/json",
66
-
67
- "x-client-transaction-id": Math.random().toString().replace("0.", ""),
68
- "x-csrf-token": this.auth.csrfToken,
69
-
70
- "x-twitter-active-user": "yes",
71
- "x-twitter-auth-type": "OAuth2Session",
72
- "x-twitter-client-language": "en",
73
-
74
- cookie: this.auth.cookies,
75
- ...headers,
76
- },
77
- body: JSON.stringify({
78
- variables: { source_tweet_id: tweetId, dark_request: false },
79
- queryId: "iQtK4dl5hBmXewYZuEOKVw",
80
- }),
81
- method: "POST",
82
- }
83
- )
84
- ).json();
85
-
86
- if (!out?.data?.unretweet) {
87
- throw new Error(`failed to unretweet: ${JSON.stringify(out, null, 2)}`);
88
- }
89
-
90
- return true;
91
- }