From 24cde1d1a880c5f041527864d54ff9b796c54cfe Mon Sep 17 00:00:00 2001 From: Taylor Caldwell Date: Wed, 3 Dec 2025 13:43:21 -0800 Subject: [PATCH] Update Javascript samples w/ XDK --- .../bookmarks/bookmarks-lookup-js-sdk.js | 92 --------- .../bookmarks/create-bookmark-js-sdk.js | 93 --------- .../bookmarks/delete-bookmark-js-sdk.js | 91 --------- ...reate_compliance_job.js => create_jobs.js} | 31 +-- ...pliance_results.js => download_results.js} | 15 +- ...list_of_compliance_jobs.js => get_jobs.js} | 29 +-- ...information_by_id.js => get_jobs_by_id.js} | 27 +-- javascript/compliance/upload_ids.js | 29 +-- javascript/lists/List-tweets.js | 47 ----- javascript/lists/Pinned-List.js | 150 --------------- javascript/lists/add_member.js | 181 +++++++----------- javascript/lists/create_a_list.js | 150 --------------- javascript/lists/create_list.js | 105 ++++++++++ javascript/lists/delete_a_list.js | 144 -------------- javascript/lists/delete_list.js | 100 ++++++++++ javascript/lists/follow_list.js | 152 --------------- javascript/lists/get_list_by_id.js | 31 +++ javascript/lists/get_list_followers.js | 29 +++ javascript/lists/get_list_members.js | 29 +++ javascript/lists/get_list_posts.js | 30 +++ javascript/lists/list-followers-lookup.js | 47 ----- javascript/lists/list-lookup-by-id.js | 47 ----- javascript/lists/list-member-lookup.js | 47 ----- javascript/lists/lookup.js | 47 ----- javascript/lists/pin_list.js | 152 --------------- javascript/lists/remove_member.js | 179 +++++++---------- javascript/lists/unfollow_list.js | 149 -------------- javascript/lists/unpin_list.js | 149 -------------- javascript/lists/update_a_list.js | 153 --------------- javascript/lists/update_list.js | 108 +++++++++++ javascript/lists/user-list-followed.js | 48 ----- javascript/lists/user-list-memberships.js | 47 ----- javascript/lists/user-owned-list-lookup.js | 47 ----- javascript/posts/block_a_user.js | 150 --------------- javascript/posts/create_post.js | 159 +++++++-------- javascript/posts/create_tweet.js | 144 -------------- javascript/posts/delete_post.js | 150 +++++++-------- javascript/posts/delete_tweet.js | 142 -------------- javascript/posts/full-archive-search.js | 51 ----- javascript/posts/full_archive_tweet_counts.js | 51 ----- javascript/posts/get_liking_users.js | 106 ++++++++++ javascript/posts/get_post_counts_all.js | 30 +++ javascript/posts/get_post_counts_recent.js | 30 +++ javascript/posts/get_posts_by_ids.js | 37 ++++ .../posts/get_posts_by_ids_user_context.js | 109 +++++++++++ javascript/posts/get_quoted_posts.js | 51 +++++ javascript/posts/get_reposted_by.js | 54 ++++++ .../posts/get_tweets_with_bearer_token.js | 53 ----- .../posts/get_tweets_with_user_context.js | 150 --------------- javascript/posts/like_a_tweet.js | 148 -------------- javascript/posts/liked_tweets.js | 46 ----- javascript/posts/liking_users.js | 49 ----- javascript/posts/lookup.js | 47 ----- javascript/posts/quote_tweets.js | 74 ------- javascript/posts/recent_search.js | 51 ----- javascript/posts/recent_tweet_counts.js | 50 ----- javascript/posts/retweet_a_tweet.js | 148 -------------- javascript/posts/retweeted_by.js | 49 ----- javascript/posts/search_all.js | 50 +++++ javascript/posts/search_recent.js | 69 ++++--- javascript/posts/unblock_a_user.js | 149 -------------- javascript/posts/undo_a_retweet.js | 145 -------------- javascript/posts/unlike_a_tweet.js | 145 -------------- javascript/spaces/get_spaces_by_ids.js | 31 +++ javascript/spaces/lookup.js | 45 ----- javascript/spaces/search_spaces.js | 39 +--- javascript/spaces/spaces_lookup.js | 50 ----- javascript/streams/filtered_stream.js | 160 ---------------- javascript/streams/sampled_stream.js | 60 ------ javascript/streams/stream_posts_filtered.js | 72 +++++++ javascript/streams/stream_posts_sample.js | 47 +++++ .../reverse-chron-home-timeline-js-sdk.js | 92 --------- .../timelines/reverse-chron-home-timeline.js | 142 -------------- javascript/timelines/user_mentions.js | 74 ------- javascript/timelines/user_posts.js | 48 ----- javascript/timelines/user_tweets.js | 79 -------- javascript/usage/get_usage.js | 27 +++ javascript/usage/get_usage_tweets.js | 44 ----- javascript/users/block/get_blocking.js | 101 ++++++++++ javascript/users/bookmark/create_bookmark.js | 107 +++++++++++ javascript/users/bookmark/delete_bookmark.js | 107 +++++++++++ javascript/users/bookmark/get_bookmarks.js | 111 +++++++++++ javascript/users/follow/get_followers.js | 44 +++++ .../users/follow/get_followers_paginated.js | 56 ++++++ .../users/follow/get_following_paginated.js | 55 ++++++ javascript/users/followers.js | 48 ----- javascript/users/followers_lookup.js | 67 ------- javascript/users/following_lookup.js | 67 ------- javascript/users/get_users_by_usernames.js | 31 +++ .../get_users_by_usernames_user_context.js | 108 +++++++++++ javascript/users/get_users_me.js | 100 ++++++++++ .../users/get_users_me_with_user_context.js | 146 -------------- .../users/get_users_with_bearer_token.js | 53 ----- .../users/get_users_with_user_context.js | 150 --------------- javascript/users/like/get_liked_posts.js | 130 +++++++++++++ javascript/users/like/like_post.js | 104 ++++++++++ javascript/users/like/unlike_post.js | 104 ++++++++++ javascript/users/lists/follow_list.js | 104 ++++++++++ javascript/users/lists/get_followed_lists.js | 29 +++ .../users/lists/get_list_memberships.js | 29 +++ javascript/users/lists/get_owned_lists.js | 29 +++ javascript/users/lists/pin_list.js | 104 ++++++++++ javascript/users/lists/unfollow_list.js | 104 ++++++++++ javascript/users/lists/unpin_list.js | 104 ++++++++++ javascript/users/lookup.js | 46 ----- javascript/users/lookup_blocks.js | 140 -------------- javascript/users/lookup_mutes.js | 142 -------------- javascript/users/mute/get_muting.js | 101 ++++++++++ javascript/users/mute/mute_user.js | 105 ++++++++++ javascript/users/mute/unmute_user.js | 104 ++++++++++ javascript/users/mute_a_user.js | 150 --------------- javascript/users/repost/repost_post.js | 104 ++++++++++ javascript/users/repost/unrepost_post.js | 104 ++++++++++ .../users/timeline/get_home_timeline.js | 101 ++++++++++ javascript/users/timeline/get_mentions.js | 51 +++++ javascript/users/timeline/get_posts.js | 35 ++++ .../users/timeline/get_posts_paginated.js | 69 +++++++ javascript/users/unmute_a_user.js | 145 -------------- 118 files changed, 3866 insertions(+), 6195 deletions(-) delete mode 100644 javascript/bookmarks/bookmarks-lookup-js-sdk.js delete mode 100644 javascript/bookmarks/create-bookmark-js-sdk.js delete mode 100644 javascript/bookmarks/delete-bookmark-js-sdk.js rename javascript/compliance/{create_compliance_job.js => create_jobs.js} (52%) rename javascript/compliance/{download_compliance_results.js => download_results.js} (69%) rename javascript/compliance/{get_list_of_compliance_jobs.js => get_jobs.js} (52%) rename javascript/compliance/{get_compliance_job_information_by_id.js => get_jobs_by_id.js} (50%) delete mode 100644 javascript/lists/List-tweets.js delete mode 100644 javascript/lists/Pinned-List.js delete mode 100644 javascript/lists/create_a_list.js create mode 100644 javascript/lists/create_list.js delete mode 100644 javascript/lists/delete_a_list.js create mode 100644 javascript/lists/delete_list.js delete mode 100644 javascript/lists/follow_list.js create mode 100644 javascript/lists/get_list_by_id.js create mode 100644 javascript/lists/get_list_followers.js create mode 100644 javascript/lists/get_list_members.js create mode 100644 javascript/lists/get_list_posts.js delete mode 100644 javascript/lists/list-followers-lookup.js delete mode 100644 javascript/lists/list-lookup-by-id.js delete mode 100644 javascript/lists/list-member-lookup.js delete mode 100644 javascript/lists/lookup.js delete mode 100644 javascript/lists/pin_list.js delete mode 100644 javascript/lists/unfollow_list.js delete mode 100644 javascript/lists/unpin_list.js delete mode 100644 javascript/lists/update_a_list.js create mode 100644 javascript/lists/update_list.js delete mode 100644 javascript/lists/user-list-followed.js delete mode 100644 javascript/lists/user-list-memberships.js delete mode 100644 javascript/lists/user-owned-list-lookup.js delete mode 100644 javascript/posts/block_a_user.js delete mode 100644 javascript/posts/create_tweet.js delete mode 100644 javascript/posts/delete_tweet.js delete mode 100644 javascript/posts/full-archive-search.js delete mode 100644 javascript/posts/full_archive_tweet_counts.js create mode 100644 javascript/posts/get_liking_users.js create mode 100644 javascript/posts/get_post_counts_all.js create mode 100644 javascript/posts/get_post_counts_recent.js create mode 100644 javascript/posts/get_posts_by_ids.js create mode 100644 javascript/posts/get_posts_by_ids_user_context.js create mode 100644 javascript/posts/get_quoted_posts.js create mode 100644 javascript/posts/get_reposted_by.js delete mode 100644 javascript/posts/get_tweets_with_bearer_token.js delete mode 100644 javascript/posts/get_tweets_with_user_context.js delete mode 100644 javascript/posts/like_a_tweet.js delete mode 100644 javascript/posts/liked_tweets.js delete mode 100644 javascript/posts/liking_users.js delete mode 100644 javascript/posts/lookup.js delete mode 100644 javascript/posts/quote_tweets.js delete mode 100644 javascript/posts/recent_search.js delete mode 100644 javascript/posts/recent_tweet_counts.js delete mode 100644 javascript/posts/retweet_a_tweet.js delete mode 100644 javascript/posts/retweeted_by.js create mode 100644 javascript/posts/search_all.js delete mode 100644 javascript/posts/unblock_a_user.js delete mode 100644 javascript/posts/undo_a_retweet.js delete mode 100644 javascript/posts/unlike_a_tweet.js create mode 100644 javascript/spaces/get_spaces_by_ids.js delete mode 100644 javascript/spaces/lookup.js delete mode 100644 javascript/spaces/spaces_lookup.js delete mode 100644 javascript/streams/filtered_stream.js delete mode 100644 javascript/streams/sampled_stream.js create mode 100644 javascript/streams/stream_posts_filtered.js create mode 100644 javascript/streams/stream_posts_sample.js delete mode 100644 javascript/timelines/reverse-chron-home-timeline-js-sdk.js delete mode 100644 javascript/timelines/reverse-chron-home-timeline.js delete mode 100644 javascript/timelines/user_mentions.js delete mode 100644 javascript/timelines/user_posts.js delete mode 100644 javascript/timelines/user_tweets.js create mode 100644 javascript/usage/get_usage.js delete mode 100644 javascript/usage/get_usage_tweets.js create mode 100644 javascript/users/block/get_blocking.js create mode 100644 javascript/users/bookmark/create_bookmark.js create mode 100644 javascript/users/bookmark/delete_bookmark.js create mode 100644 javascript/users/bookmark/get_bookmarks.js create mode 100644 javascript/users/follow/get_followers.js create mode 100644 javascript/users/follow/get_followers_paginated.js create mode 100644 javascript/users/follow/get_following_paginated.js delete mode 100644 javascript/users/followers.js delete mode 100644 javascript/users/followers_lookup.js delete mode 100644 javascript/users/following_lookup.js create mode 100644 javascript/users/get_users_by_usernames.js create mode 100644 javascript/users/get_users_by_usernames_user_context.js create mode 100644 javascript/users/get_users_me.js delete mode 100644 javascript/users/get_users_me_with_user_context.js delete mode 100644 javascript/users/get_users_with_bearer_token.js delete mode 100644 javascript/users/get_users_with_user_context.js create mode 100644 javascript/users/like/get_liked_posts.js create mode 100644 javascript/users/like/like_post.js create mode 100644 javascript/users/like/unlike_post.js create mode 100644 javascript/users/lists/follow_list.js create mode 100644 javascript/users/lists/get_followed_lists.js create mode 100644 javascript/users/lists/get_list_memberships.js create mode 100644 javascript/users/lists/get_owned_lists.js create mode 100644 javascript/users/lists/pin_list.js create mode 100644 javascript/users/lists/unfollow_list.js create mode 100644 javascript/users/lists/unpin_list.js delete mode 100644 javascript/users/lookup.js delete mode 100644 javascript/users/lookup_blocks.js delete mode 100644 javascript/users/lookup_mutes.js create mode 100644 javascript/users/mute/get_muting.js create mode 100644 javascript/users/mute/mute_user.js create mode 100644 javascript/users/mute/unmute_user.js delete mode 100644 javascript/users/mute_a_user.js create mode 100644 javascript/users/repost/repost_post.js create mode 100644 javascript/users/repost/unrepost_post.js create mode 100644 javascript/users/timeline/get_home_timeline.js create mode 100644 javascript/users/timeline/get_mentions.js create mode 100644 javascript/users/timeline/get_posts.js create mode 100644 javascript/users/timeline/get_posts_paginated.js delete mode 100644 javascript/users/unmute_a_user.js diff --git a/javascript/bookmarks/bookmarks-lookup-js-sdk.js b/javascript/bookmarks/bookmarks-lookup-js-sdk.js deleted file mode 100644 index b6da60c..0000000 --- a/javascript/bookmarks/bookmarks-lookup-js-sdk.js +++ /dev/null @@ -1,92 +0,0 @@ -const { Client, auth } = require("twitter-api-sdk"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -//Helper function to parse callback -const getQueryStringParams = (query) => { - return query - ? (/^[?#]/.test(query) ? query.slice(1) : query) - .split(/[\?\&]/) - .reduce((params, param) => { - let [key, value] = param.split("="); - params[key] = value - ? decodeURIComponent(value.replace(/\+/g, " ")) - : ""; - return params; - }, {}) - : {}; -}; - -//Helper terminal input function -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CLIENT_ID='YOUR-CLIENT-ID' -// export CLIENET_SECRET='YOUR-CLIENT-SECRET' -const CLIENT_ID = process.env.CLIENT_ID; -const CLIENT_SECRET = process.env.CLIENT_SECRET; - -// Optional parameters for additional payload data -const params = { - expansions: "author_id", - "user.fields": ["username", "created_at"], - "tweet.fields": ["geo", "entities", "context_annotations"], -}; - -(async () => { - const authClient = new auth.OAuth2User({ - client_id: CLIENT_ID, - client_secret: CLIENT_SECRET, - callback: "https://www.example.com/oauth", - scopes: ["tweet.read", "users.read", "bookmark.read"], - }); - - const client = new Client(authClient); - const STATE = "my-state"; - - //Get authorization - const authUrl = authClient.generateAuthURL({ - state: STATE, - code_challenge: "challenge", - }); - - console.log(`Please go here and authorize:`, authUrl); - - //Input users callback url in termnial - const redirectCallback = await input("Paste the redirected callback here: "); - - try { - //Parse callback - const { state, code } = getQueryStringParams(redirectCallback); - if (state !== STATE) { - console.log("State isn't matching"); - } - //Gets access token - await authClient.requestAccessToken(code); - - //Get the user ID - const { - data: { id }, - } = await client.users.findMyUser(); - - //Makes api call - const getBookmark = await client.bookmarks.getUsersIdBookmarks(id, params); - console.dir(getBookmark, { - depth: null, - }); - process.exit(); - } catch (error) { - console.log(error); - } -})(); diff --git a/javascript/bookmarks/create-bookmark-js-sdk.js b/javascript/bookmarks/create-bookmark-js-sdk.js deleted file mode 100644 index 8c28b34..0000000 --- a/javascript/bookmarks/create-bookmark-js-sdk.js +++ /dev/null @@ -1,93 +0,0 @@ -const { Client, auth } = require("twitter-api-sdk"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -//Helper function to parse callback -const getQueryStringParams = (query) => { - return query - ? (/^[?#]/.test(query) ? query.slice(1) : query) - .split(/[\?\&]/) - .reduce((params, param) => { - let [key, value] = param.split("="); - params[key] = value - ? decodeURIComponent(value.replace(/\+/g, " ")) - : ""; - return params; - }, {}) - : {}; -}; - -//Helper terminal input function -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CLIENT_ID='YOUR-CLIENT-ID' -// export CLIENET_SECRET='YOUR-CLIENT-SECRET' -const CLIENT_ID = process.env.CLIENT_ID; -const CLIENT_SECRET = process.env.CLIENT_SECRET; - -// Include the ID of the Tweet you wish to bookmark -const params = { - tweet_id: "replace-with-tweet-id", -}; - -(async () => { - const authClient = new auth.OAuth2User({ - client_id: CLIENT_ID, - client_secret: CLIENT_SECRET, - callback: "https://www.example.com/oauth", - scopes: ["tweet.read", "users.read", "bookmark.write"], - }); - - const client = new Client(authClient); - const STATE = "my-state"; - - //Get authorization - const authUrl = authClient.generateAuthURL({ - state: STATE, - code_challenge: "challenge", - }); - - console.log(`Please go here and authorize:`, authUrl); - - //Input users callback url in termnial - const redirectCallback = await input("Paste the redirected callback here: "); - - try { - //Parse callback - const { state, code } = getQueryStringParams(redirectCallback); - if (state !== STATE) { - console.log("State isn't matching"); - } - //Gets access token - await authClient.requestAccessToken(code); - - //Get the user ID - const { - data: { id }, - } = await client.users.findMyUser(); - - //Makes api call - const postBookmark = await client.bookmarks.postUsersIdBookmarks( - id, - params - ); - console.dir(postBookmark, { - depth: null, - }); - process.exit(); - } catch (error) { - console.log(error); - } -})(); diff --git a/javascript/bookmarks/delete-bookmark-js-sdk.js b/javascript/bookmarks/delete-bookmark-js-sdk.js deleted file mode 100644 index 91a5625..0000000 --- a/javascript/bookmarks/delete-bookmark-js-sdk.js +++ /dev/null @@ -1,91 +0,0 @@ -const { Client, auth } = require("twitter-api-sdk"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -//Helper function to parse callback -const getQueryStringParams = (query) => { - return query - ? (/^[?#]/.test(query) ? query.slice(1) : query) - .split(/[\?\&]/) - .reduce((params, param) => { - let [key, value] = param.split("="); - params[key] = value - ? decodeURIComponent(value.replace(/\+/g, " ")) - : ""; - return params; - }, {}) - : {}; -}; - -//Helper terminal input function -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CLIENT_ID='YOUR-CLIENT-ID' -// export CLIENET_SECRET='YOUR-CLIENT-SECRET' -const CLIENT_ID = process.env.CLIENT_ID; -const CLIENT_SECRET = process.env.CLIENT_SECRET; - -// Include the ID of the Tweet you wish to unbookmark -const tweetId = "replace-with-tweet-id"; - -(async () => { - const authClient = new auth.OAuth2User({ - client_id: CLIENT_ID, - client_secret: CLIENT_SECRET, - callback: "https://www.example.com/oauth", - scopes: ["tweet.read", "users.read", "bookmark.write"], - }); - - const client = new Client(authClient); - const STATE = "my-state"; - - //Get authorization - const authUrl = authClient.generateAuthURL({ - state: STATE, - code_challenge: "challenge", - }); - - console.log(`Please go here and authorize:`, authUrl); - - //Input users callback url in termnial - const redirectCallback = await input("Paste the redirected callback here: "); - - try { - //Parse callback - const { state, code } = getQueryStringParams(redirectCallback); - if (state !== STATE) { - console.log("State isn't matching"); - } - //Gets access token - await authClient.requestAccessToken(code); - - //Get the user ID - const { - data: { id }, - } = await client.users.findMyUser(); - - //Makes api call - const deleteBookmark = await client.bookmarks.usersIdBookmarksDelete( - id, - tweetId - ); - console.dir(deleteBookmark, { - depth: null, - }); - process.exit(); - } catch (error) { - console.log(error); - } -})(); diff --git a/javascript/compliance/create_compliance_job.js b/javascript/compliance/create_jobs.js similarity index 52% rename from javascript/compliance/create_compliance_job.js rename to javascript/compliance/create_jobs.js index 14e6dee..2a40870 100644 --- a/javascript/compliance/create_compliance_job.js +++ b/javascript/compliance/create_jobs.js @@ -1,40 +1,23 @@ -const needle = require('needle'); +const { Client } = require('@xdevplatform/xdk'); // The code below sets the bearer token from your environment variables // To set environment variables on macOS or Linux, run the export command below from the terminal: // export BEARER_TOKEN='YOUR-TOKEN' const token = process.env.BEARER_TOKEN; - -const endpointUrl = 'https://api.x.com/2/compliance/jobs' +const client = new Client({ bearerToken: token }); // For User Compliance Job, replace type value with users instead of tweets // Also replace the name value with your desired job name const data = { - "type": "tweets", - "name": 'my_batch_compliance_job' -} - -async function makeRequest() { - - const res = await needle.post(endpointUrl, { - json: data, - headers: { - "User-Agent": "v2BatchComplianceJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} + type: "tweets", + name: 'my_batch_compliance_job' +}; (async () => { try { // Make request - const response = await makeRequest(); + const response = await client.compliance.createJobs(data); + console.dir(response, { depth: null }); diff --git a/javascript/compliance/download_compliance_results.js b/javascript/compliance/download_results.js similarity index 69% rename from javascript/compliance/download_compliance_results.js rename to javascript/compliance/download_results.js index f23a960..3896c86 100644 --- a/javascript/compliance/download_compliance_results.js +++ b/javascript/compliance/download_results.js @@ -1,14 +1,15 @@ -const needle = require('needle'); - // Replace with your job download_url downloadUrl = '' async function getRequest() { + const res = await fetch(downloadUrl, { + headers: { + 'Accept-Encoding': 'gzip, deflate, br' + } + }) - const res = await needle('get', downloadUrl, { compressed: true }) - - if (res.body) { - return res.body.toString('utf8'); + if (res.ok) { + return await res.text(); } else { throw new Error('Unsuccessful request'); } @@ -28,4 +29,4 @@ async function getRequest() { process.exit(-1); } process.exit(); -})(); +})(); \ No newline at end of file diff --git a/javascript/compliance/get_list_of_compliance_jobs.js b/javascript/compliance/get_jobs.js similarity index 52% rename from javascript/compliance/get_list_of_compliance_jobs.js rename to javascript/compliance/get_jobs.js index b52e55e..4a94e5b 100644 --- a/javascript/compliance/get_list_of_compliance_jobs.js +++ b/javascript/compliance/get_jobs.js @@ -1,38 +1,21 @@ -const needle = require('needle'); +const { Client } = require('@xdevplatform/xdk'); // The code below sets the bearer token from your environment variables // To set environment variables on macOS or Linux, run the export command below from the terminal: // export BEARER_TOKEN='YOUR-TOKEN' const token = process.env.BEARER_TOKEN; - -const endpointUrl = 'https://api.x.com/2/compliance/jobs' +const client = new Client({ bearerToken: token }); // For User Compliance job, replace the value for type with users const params = { - "type": "tweets", -} - -async function getRequest() { - - const res = await needle('get', endpointUrl, params, { - headers: { - "User-Agent": "v2BatchComplianceJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} + type: "tweets" +}; (async () => { - try { // Make request - const response = await getRequest(); + const response = await client.compliance.getJobs(params); + console.dir(response, { depth: null }); diff --git a/javascript/compliance/get_compliance_job_information_by_id.js b/javascript/compliance/get_jobs_by_id.js similarity index 50% rename from javascript/compliance/get_compliance_job_information_by_id.js rename to javascript/compliance/get_jobs_by_id.js index 18e85a9..37a8ddd 100644 --- a/javascript/compliance/get_compliance_job_information_by_id.js +++ b/javascript/compliance/get_jobs_by_id.js @@ -1,36 +1,19 @@ -const needle = require('needle'); +const { Client } = require('@xdevplatform/xdk'); // The code below sets the bearer token from your environment variables // To set environment variables on macOS or Linux, run the export command below from the terminal: // export BEARER_TOKEN='YOUR-TOKEN' const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); // Replace with your job ID -jobId = '' - -const endpointUrl = `https://api.x.com/2/compliance/jobs/${jobId}` - -async function getRequest() { - - const res = await needle('get', endpointUrl, { - headers: { - "User-Agent": "v2BatchComplianceJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} +const jobId = ''; (async () => { - try { // Make request - const response = await getRequest(); + const response = await client.compliance.getJobsById(jobId); + console.dir(response, { depth: null }); diff --git a/javascript/compliance/upload_ids.js b/javascript/compliance/upload_ids.js index 73ccc5d..c9dda47 100644 --- a/javascript/compliance/upload_ids.js +++ b/javascript/compliance/upload_ids.js @@ -1,37 +1,42 @@ -const got = require('got'); const fs = require('fs'); // Replace with your job download_url -uploadUrl = '' +const uploadUrl = ''; -// Replace with your file path that contains the list of Tweet IDs or User IDs, one ID per line -const readStream = fs.createReadStream('/path/to/file'); +// Replace with your file path that contains the list of Post IDs or User IDs, one ID per line +const filePath = '/path/to/file'; async function getRequest() { - - const res = await got.put(uploadUrl, { - body: readStream, + const readStream = fs.createReadStream(filePath); + const fileBuffer = await new Promise((resolve, reject) => { + const chunks = []; + readStream.on('data', chunk => chunks.push(chunk)); + readStream.on('end', () => resolve(Buffer.concat(chunks))); + readStream.on('error', reject); + }); + + const res = await fetch(uploadUrl, { + method: 'PUT', + body: fileBuffer, headers: { "Content-Type": "text/plain" } - }) + }); - if (res.statusCode == 200) { - return res.statusCode; + if (res.ok) { + return res.status; } else { throw new Error('Unsuccessful request'); } } (async () => { - try { // Make request const response = await getRequest(); console.dir(response, { depth: null }); - } catch (e) { console.log(e); process.exit(-1); diff --git a/javascript/lists/List-tweets.js b/javascript/lists/List-tweets.js deleted file mode 100644 index 57783fc..0000000 --- a/javascript/lists/List-tweets.js +++ /dev/null @@ -1,47 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; -const id = "list-id"; - -const endpointURL = `https://api.x.com/2/lists/${id}/tweets`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the Tweet ID and text are returned - const params = { - "tweet.fields": "lang,author_id", // Edit optional query parameters here - expansions: "author_id", // expansions is used to include the user object - "user.fields": "created_at", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2ListTweetsLookupJS", - authorization: `Bearer ${token}`, - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/Pinned-List.js b/javascript/lists/Pinned-List.js deleted file mode 100644 index d11de05..0000000 --- a/javascript/lists/Pinned-List.js +++ /dev/null @@ -1,150 +0,0 @@ -// Pin a list using PIN-based OAuth to authorize the user -// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const needle = require("needle"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - -const params = { - "list.fields": `owner_id`, // Edit optional query parameters here - expansions: `owner_id`, // expansions is used to include the user object - "user.fields": `created_at,verified`, // Edit optional query parameters here -}; - -const endpointURL = `https://api.x.com/2/users/${id}/pinned_lists`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "GET", - }, - token - ) - ); - - const req = await needle("get", endpointURL, { - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2pinListLookupJS", - "content-type": "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/add_member.js b/javascript/lists/add_member.js index 0c5befa..bdb057a 100644 --- a/javascript/lists/add_member.js +++ b/javascript/lists/add_member.js @@ -1,50 +1,33 @@ -// Add member to a list using PIN-based OAuth to authorize the user +// Add member to a list using OAuth 2.0 to authorize the user // https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); const readline = require("readline").createInterface({ input: process.stdin, output: process.stdout, }); -// The code below sets the consumer key and consumer secret from your environment variables +// The code below sets the client ID and client secret from your environment variables // To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; // Be sure to replace your-list-id with your own list ID or one of an authenticated user -const id = "your-list-id"; +const listId = "your-list-id"; // Be sure to replace user-id-to-add with the user id you wish to add. // You can find a user ID by using the user lookup endpoint -const data = { - user_id: "user-id-to-add", -}; - -const endpointURL = `https://api.x.com/2/lists/${id}/members`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); +const userId = "user-id-to-add"; async function input(prompt) { - return new Promise(async (resolve, reject) => { + return new Promise((resolve) => { readline.question(prompt, (out) => { readline.close(); resolve(out); @@ -52,94 +35,64 @@ async function input(prompt) { }); } -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'list.read', 'list.write', 'offline.access'] + }; -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} + const oauth2 = new OAuth2(oauth2Config); -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "POST", - }, - token - ) - ); + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); - const req = await got.post(endpointURL, { - json: data, - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2addMemberJS", - "content-type": "application/json", - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.lists.addMember(listId, { body: { user_id: userId } }); console.dir(response, { depth: null, }); diff --git a/javascript/lists/create_a_list.js b/javascript/lists/create_a_list.js deleted file mode 100644 index 4a60525..0000000 --- a/javascript/lists/create_a_list.js +++ /dev/null @@ -1,150 +0,0 @@ -// Create a new list using PIN-based OAuth to authorize the user -// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to add replace name-of-list with the name you wish to call the list. -// description and private keys are optional -const data = { - name: "name-of-list", - description: "description-of-list", - private: false, -}; - -const endpointURL = `https://api.x.com/2/lists`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "POST", - }, - token - ) - ); - - const req = await got.post(endpointURL, { - json: data, - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2createListJS", - "content-type": "application/json", - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/create_list.js b/javascript/lists/create_list.js new file mode 100644 index 0000000..3b48aec --- /dev/null +++ b/javascript/lists/create_list.js @@ -0,0 +1,105 @@ +// Create a new list using OAuth 2.0 to authorize the user +// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to add replace name-of-list with the name you wish to call the list. +// description and private keys are optional +const data = { + name: "name-of-list", + description: "description-of-list", + private: false, +}; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'list.read', 'list.write', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.lists.create({ body: data }); + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/lists/delete_a_list.js b/javascript/lists/delete_a_list.js deleted file mode 100644 index 75d55de..0000000 --- a/javascript/lists/delete_a_list.js +++ /dev/null @@ -1,144 +0,0 @@ -// Delete an existing list the authenticated user owns - using PIN-based OAuth to authorize the user -// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to add replace the your-list-id with the id of the list you wish to delete. -const target_list_id = "your-list-id"; - -const endpointURL = `https://api.x.com/2/lists/${target_list_id}`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "DELETE", - }, - token - ) - ); - - const req = await got.delete(endpointURL, { - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2deleteListJS", - "content-type": "application/json", - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/delete_list.js b/javascript/lists/delete_list.js new file mode 100644 index 0000000..6a2421f --- /dev/null +++ b/javascript/lists/delete_list.js @@ -0,0 +1,100 @@ +// Delete an existing list the authenticated user owns - using OAuth 2.0 to authorize the user +// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to add replace the your-list-id with the id of the list you wish to delete. +const targetListId = "your-list-id"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'list.read', 'list.write', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.lists.delete(targetListId); + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/lists/follow_list.js b/javascript/lists/follow_list.js deleted file mode 100644 index ed0cc4b..0000000 --- a/javascript/lists/follow_list.js +++ /dev/null @@ -1,152 +0,0 @@ -// Follow a list using PIN-based OAuth to authorize the user -// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - -// Be sure to add replace list-id-to-follow with the list id you wish to follow. - -const data = { - list_id: "list-id-to-follow", -}; - -const endpointURL = `https://api.x.com/2/users/${id}/followed_lists`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "POST", - }, - token - ) - ); - - const req = await got.post(endpointURL, { - json: data, - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2followListJS", - "content-type": "application/json", - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/get_list_by_id.js b/javascript/lists/get_list_by_id.js new file mode 100644 index 0000000..d1eb1e1 --- /dev/null +++ b/javascript/lists/get_list_by_id.js @@ -0,0 +1,31 @@ +/** + * List Lookup - X API v2 + * + * Endpoint: GET https://api.x.com/2/lists/:id + * Docs: https://developer.x.com/en/docs/twitter-api/lists/list-lookup/api-reference/get-lists-id + * + * Authentication: Bearer Token (App-only) or OAuth (User Context) + * Required env vars: BEARER_TOKEN + */ + +const { Client } = require('@xdevplatform/xdk'); + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +// Replace with the list ID you want to look up +const listId = "84839422"; + +(async () => { + try { + const response = await client.lists.getById(listId, { + listFields: ['created_at', 'follower_count', 'member_count', 'owner_id', 'description'] + }); + + console.dir(response, { depth: null }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/lists/get_list_followers.js b/javascript/lists/get_list_followers.js new file mode 100644 index 0000000..6ccc1bc --- /dev/null +++ b/javascript/lists/get_list_followers.js @@ -0,0 +1,29 @@ +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); +const id = "list-id"; + +(async () => { + try { + // These are the parameters for the API request + // by default, only the User ID and name are returned + const response = await client.lists.getFollowers(id, { + userFields: ['pinned_tweet_id', 'created_at'], // Edit optional query parameters here + expansions: ['pinned_tweet_id'], // expansions is used to include the Post object + tweetFields: ['created_at'] // Edit optional query parameters here + }); + + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/lists/get_list_members.js b/javascript/lists/get_list_members.js new file mode 100644 index 0000000..b366185 --- /dev/null +++ b/javascript/lists/get_list_members.js @@ -0,0 +1,29 @@ +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); +const id = "list-id"; + +(async () => { + try { + // These are the parameters for the API request + // by default, only the User ID and name are returned + const response = await client.lists.getMembers(id, { + userFields: ['pinned_tweet_id', 'created_at'], // Edit optional query parameters here + expansions: ['pinned_tweet_id'], // expansions is used to include the Post object + tweetFields: ['created_at'] // Edit optional query parameters here + }); + + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/lists/get_list_posts.js b/javascript/lists/get_list_posts.js new file mode 100644 index 0000000..b8e7b67 --- /dev/null +++ b/javascript/lists/get_list_posts.js @@ -0,0 +1,30 @@ +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); +const id = "list-id"; + +(async () => { + try { + // These are the parameters for the API request + // by default, only the Post ID and text are returned + const response = await client.lists.getPosts(id, { + tweetFields: ['lang', 'author_id'], // Edit optional query parameters here + expansions: ['author_id'], // expansions is used to include the user object + userFields: ['created_at'] // Edit optional query parameters here + }); + + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); + diff --git a/javascript/lists/list-followers-lookup.js b/javascript/lists/list-followers-lookup.js deleted file mode 100644 index abae1a7..0000000 --- a/javascript/lists/list-followers-lookup.js +++ /dev/null @@ -1,47 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; -const id = "list-id"; - -const endpointURL = `https://api.x.com/2/lists/${id}/followers`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the User ID and name are returned - const params = { - "user.fields": "pinned_tweet_id,created_at", // Edit optional query parameters here - expansions: "pinned_tweet_id", // expansions is used to include the Tweet object - "tweet.fields": "created_at", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2ListFollowersLookupJS", - authorization: `Bearer ${token}`, - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/list-lookup-by-id.js b/javascript/lists/list-lookup-by-id.js deleted file mode 100644 index 1a04544..0000000 --- a/javascript/lists/list-lookup-by-id.js +++ /dev/null @@ -1,47 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; -const id = "list-id"; - -const endpointURL = `https://api.x.com/2/lists/${id}`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the List ID and name are returned - const params = { - "list.fields": "owner_id", // Edit optional query parameters here - expansions: "owner_id", // expansions is used to include the user object - "user.fields": "created_at,verified", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2ListLookupJS", - authorization: `Bearer ${token}`, - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/list-member-lookup.js b/javascript/lists/list-member-lookup.js deleted file mode 100644 index ebd86a9..0000000 --- a/javascript/lists/list-member-lookup.js +++ /dev/null @@ -1,47 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; -const id = "list-id"; - -const endpointURL = `https://api.x.com/2/lists/${id}/members`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the User ID and name are returned - const params = { - "user.fields": "pinned_tweet_id,created_at", // Edit optional query parameters here - expansions: "pinned_tweet_id", // expansions is used to include the Tweet object - "tweet.fields": "created_at", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2ListMembersLookupJS", - authorization: `Bearer ${token}`, - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/lookup.js b/javascript/lists/lookup.js deleted file mode 100644 index 868e8d3..0000000 --- a/javascript/lists/lookup.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * List Lookup - X API v2 - * - * Endpoint: GET https://api.x.com/2/lists/:id - * Docs: https://developer.x.com/en/docs/twitter-api/lists/list-lookup/api-reference/get-lists-id - * - * Authentication: Bearer Token (App-only) or OAuth (User Context) - * Required env vars: BEARER_TOKEN - */ - -const needle = require('needle'); - -const token = process.env.BEARER_TOKEN; - -// Replace with the list ID you want to look up -const listId = "84839422"; -const endpointURL = `https://api.x.com/2/lists/${listId}`; - -async function getRequest() { - const params = { - "list.fields": "created_at,follower_count,member_count,owner_id,description" - }; - - const res = await needle('get', endpointURL, params, { - headers: { - "User-Agent": "v2ListLookupJS", - "authorization": `Bearer ${token}` - } - }); - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - try { - const response = await getRequest(); - console.dir(response, { depth: null }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/pin_list.js b/javascript/lists/pin_list.js deleted file mode 100644 index a2a2ac6..0000000 --- a/javascript/lists/pin_list.js +++ /dev/null @@ -1,152 +0,0 @@ -// Pin a list using PIN-based OAuth to authorize the user -// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - -// Be sure to add replace list-id-to-pin with the list id you wish to pin. - -const data = { - list_id: "list-id-to-pin", -}; - -const endpointURL = `https://api.x.com/2/users/${id}/pinned_lists`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "POST", - }, - token - ) - ); - - const req = await got.post(endpointURL, { - json: data, - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2pinListJS", - "content-type": "application/json", - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/remove_member.js b/javascript/lists/remove_member.js index 0059a2b..5d290af 100644 --- a/javascript/lists/remove_member.js +++ b/javascript/lists/remove_member.js @@ -1,49 +1,33 @@ -// Remove member from a list using PIN-based OAuth to authorize the user +// Remove member from a list using OAuth 2.0 to authorize the user // https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); const readline = require("readline").createInterface({ input: process.stdin, output: process.stdout, }); -// The code below sets the consumer key and consumer secret from your environment variables +// The code below sets the client ID and client secret from your environment variables // To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; // Be sure to replace your-list-id with your own list ID or one of an authenticated user -const id = "your-list-id"; +const listId = "your-list-id"; // Be sure to replace user-id-to-remove with the user id you wish to remove. // You can find a user ID by using the user lookup endpoint - -const user_id = "user-id-to-remove"; - -const endpointURL = `https://api.x.com/2/lists/${id}/members/${user_id}`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); +const userId = "user-id-to-remove"; async function input(prompt) { - return new Promise(async (resolve, reject) => { + return new Promise((resolve) => { readline.question(prompt, (out) => { readline.close(); resolve(out); @@ -51,93 +35,64 @@ async function input(prompt) { }); } -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'list.read', 'list.write', 'offline.access'] + }; -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} + const oauth2 = new OAuth2(oauth2Config); -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "DELETE", - }, - token - ) - ); + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); - const req = await got.delete(endpointURL, { - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2removeMemberJS", - "content-type": "application/json", - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.lists.removeMemberByUserId(listId, userId); console.dir(response, { depth: null, }); diff --git a/javascript/lists/unfollow_list.js b/javascript/lists/unfollow_list.js deleted file mode 100644 index 7d47e23..0000000 --- a/javascript/lists/unfollow_list.js +++ /dev/null @@ -1,149 +0,0 @@ -// Unfollow a list using PIN-based OAuth to authorize the user -// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - -// Be sure to replace list-id-to-unfollow with the user id you wish to unfollow. - -const list_id = "list-id-to-unfollow"; - -const endpointURL = `https://api.x.com/2/users/${id}/followed_lists/${list_id}`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "DELETE", - }, - token - ) - ); - - const req = await got.delete(endpointURL, { - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2unfollowListJS", - "content-type": "application/json", - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/unpin_list.js b/javascript/lists/unpin_list.js deleted file mode 100644 index 1cfdc8c..0000000 --- a/javascript/lists/unpin_list.js +++ /dev/null @@ -1,149 +0,0 @@ -// Unpin a list using PIN-based OAuth to authorize the user -// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - -// Be sure to replace list-id-to-unpin with the user id you wish to unpin. - -const list_id = "list-id-to-unpin"; - -const endpointURL = `https://api.x.com/2/users/${id}/pinned_lists/${list_id}`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "DELETE", - }, - token - ) - ); - - const req = await got.delete(endpointURL, { - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2unpinListJS", - "content-type": "application/json", - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/update_a_list.js b/javascript/lists/update_a_list.js deleted file mode 100644 index 7c6d428..0000000 --- a/javascript/lists/update_a_list.js +++ /dev/null @@ -1,153 +0,0 @@ -// Update the metadata of an existing list the authenticated user owns - using PIN-based OAuth to authorize the user -// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to add replace update-name-of-list with the name you wish to call the list. -// name, description and private are all optional -const data = { - name: "update-name-of-list", - description: "update-description-of-list", - private: false, -}; - -// Be sure to add replace the your-list-id with the list id of the list you wish to update. -const target_list_id = "your-list-id"; - -const endpointURL = `https://api.x.com/2/lists/${target_list_id}`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "PUT", - }, - token - ) - ); - - const req = await got.put(endpointURL, { - json: data, - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2updateListJS", - "content-type": "application/json", - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/update_list.js b/javascript/lists/update_list.js new file mode 100644 index 0000000..13091af --- /dev/null +++ b/javascript/lists/update_list.js @@ -0,0 +1,108 @@ +// Update the metadata of an existing list the authenticated user owns - using OAuth 2.0 to authorize the user +// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to add replace update-name-of-list with the name you wish to call the list. +// name, description and private are all optional +const data = { + name: "update-name-of-list", + description: "update-description-of-list", + private: false, +}; + +// Be sure to add replace the your-list-id with the list id of the list you wish to update. +const targetListId = "your-list-id"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'list.read', 'list.write', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.lists.update(targetListId, { body: data }); + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/lists/user-list-followed.js b/javascript/lists/user-list-followed.js deleted file mode 100644 index 7bf4a52..0000000 --- a/javascript/lists/user-list-followed.js +++ /dev/null @@ -1,48 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; -const id = "user-id"; - -const endpointURL = `https://api.x.com/2/users/${id}/followed_lists`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the List ID and name are returned - const params = { - "list.fields": "owner_id", // Edit optional query parameters here - expansions: "owner_id", // expansions is used to include the user object - "user.fields": "created_at,verified", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2userListMembershipsJS", - authorization: `Bearer ${token}`, - "x-des-apiservices": "staging1", - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/user-list-memberships.js b/javascript/lists/user-list-memberships.js deleted file mode 100644 index fa196c4..0000000 --- a/javascript/lists/user-list-memberships.js +++ /dev/null @@ -1,47 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; -const id = "user-id"; - -const endpointURL = `https://api.x.com/2/users/${id}/list_memberships`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the List ID and name are returned - const params = { - "list.fields": "owner_id", // Edit optional query parameters here - expansions: "owner_id", // expansions is used to include the user object - "user.fields": "created_at,verified", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2userListMembershipsJS", - authorization: `Bearer ${token}`, - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/lists/user-owned-list-lookup.js b/javascript/lists/user-owned-list-lookup.js deleted file mode 100644 index f695cf8..0000000 --- a/javascript/lists/user-owned-list-lookup.js +++ /dev/null @@ -1,47 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; -const id = "user-id"; - -const endpointURL = `https://api.x.com/2/users/${id}/owned_lists`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the List ID and name are returned - const params = { - "list.fields": "owner_id", // Edit optional query parameters here - expansions: "owner_id", // expansions is used to include the user object - "user.fields": "created_at,verified", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2ListLookupJS", - authorization: `Bearer ${token}`, - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/block_a_user.js b/javascript/posts/block_a_user.js deleted file mode 100644 index 626b027..0000000 --- a/javascript/posts/block_a_user.js +++ /dev/null @@ -1,150 +0,0 @@ -// Block a user, using user authentication -// https://developer.twitter.com/en/docs/twitter-api/users/blocks/quick-start -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}) - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - -// Be sure to add replace id-to-block with the user id you wish to block. -// You can find a user ID by using the user lookup endpoint -const data = { - "target_user_id": "id-to-block" -} - -const endpointURL = `https://api.x.com/2/users/${id}/blocking`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'POST' - }, token)); - - const req = await got.post(endpointURL, { - json: data, - responseType: 'json', - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2BlockUserJS", - 'content-type': "application/json", - 'accept': "application/json" - } - }); - if (req.body) { - return req.body; - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/create_post.js b/javascript/posts/create_post.js index 956efd1..34561a0 100644 --- a/javascript/posts/create_post.js +++ b/javascript/posts/create_post.js @@ -1,47 +1,36 @@ /** * Create Post - X API v2 * - * Endpoint: POST https://api.x.com/2/tweets + * Endpoint: POST https://api.x.com/2/posts * Docs: https://developer.x.com/en/docs/twitter-api/tweets/manage-tweets/api-reference/post-tweets * - * Authentication: OAuth 1.0a (User Context) - * Required env vars: CONSUMER_KEY, CONSUMER_SECRET + * Authentication: OAuth 2.0 (User Context) + * Required env vars: CLIENT_ID, CLIENT_SECRET */ -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + const readline = require('readline').createInterface({ input: process.stdin, output: process.stdout }); -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; // The text content of the post. You can also add parameters for polls, // quote posts, reply settings, and more. const data = { - "text": "Hello world!" + text: "Hello world!" }; -const endpointURL = 'https://api.x.com/2/tweets'; -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob&x_auth_access_type=write'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; - -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - async function input(prompt) { - return new Promise(async (resolve, reject) => { + return new Promise((resolve) => { readline.question(prompt, (out) => { readline.close(); resolve(out); @@ -49,82 +38,64 @@ async function input(prompt) { }); } -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write', 'offline.access'] + }; -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} + const oauth2 = new OAuth2(oauth2Config); -async function createPost({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret - }; + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'POST' - }, token)); + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); - const req = await got.post(endpointURL, { - json: data, - responseType: 'json', - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2CreatePostJS", - 'content-type': "application/json", - 'accept': "application/json" + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); } - }); - if (req.body) { - return req.body; - } else { - throw new Error('Unsuccessful request'); - } -} -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await createPost(oAuthAccessToken); + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.posts.create(data); console.dir(response, { depth: null }); } catch (e) { console.log(e); diff --git a/javascript/posts/create_tweet.js b/javascript/posts/create_tweet.js deleted file mode 100644 index eb15cec..0000000 --- a/javascript/posts/create_tweet.js +++ /dev/null @@ -1,144 +0,0 @@ -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}); - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to add replace the text of the with the text you wish to Tweet. -// You can also add parameters to post polls, quote Tweets, Tweet with reply settings, and Tweet to Super Followers in addition to other features. -const data = { - "text": "Hello world!" -}; - -const endpointURL = `https://api.x.com/2/tweets`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob&x_auth_access_type=write'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'POST' - }, token)); - - const req = await got.post(endpointURL, { - json: data, - responseType: 'json', - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2CreateTweetJS", - 'content-type': "application/json", - 'accept': "application/json" - } - }); - if (req.body) { - return req.body; - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/delete_post.js b/javascript/posts/delete_post.js index 3d36b84..3f1447c 100644 --- a/javascript/posts/delete_post.js +++ b/javascript/posts/delete_post.js @@ -1,44 +1,33 @@ /** * Delete Post - X API v2 * - * Endpoint: DELETE https://api.x.com/2/tweets/:id + * Endpoint: DELETE https://api.x.com/2/posts/:id * Docs: https://developer.x.com/en/docs/twitter-api/tweets/manage-tweets/api-reference/delete-tweets-id * - * Authentication: OAuth 1.0a (User Context) - * Required env vars: CONSUMER_KEY, CONSUMER_SECRET + * Authentication: OAuth 2.0 (User Context) + * Required env vars: CLIENT_ID, CLIENT_SECRET */ -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + const readline = require('readline').createInterface({ input: process.stdin, output: process.stdout }); -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; // Replace with the post ID you want to delete const postId = "post-id-to-delete"; -const endpointURL = `https://api.x.com/2/tweets/${postId}`; - -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob&x_auth_access_type=write'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; - -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); async function input(prompt) { - return new Promise(async (resolve, reject) => { + return new Promise((resolve) => { readline.question(prompt, (out) => { readline.close(); resolve(out); @@ -46,75 +35,64 @@ async function input(prompt) { }); } -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write','offline.access'] + }; -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} + const oauth2 = new OAuth2(oauth2Config); -async function deletePost({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret - }; + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'DELETE' - }, token)); + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); - const req = await got.delete(endpointURL, { - responseType: 'json', - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2DeletePostJS" + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); } - }); - if (req.body) { - return req.body; - } else { - throw new Error('Unsuccessful request'); - } -} -(async () => { - try { - const oAuthRequestToken = await requestToken(); - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - const response = await deletePost(oAuthAccessToken); + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.posts.delete(postId); console.dir(response, { depth: null }); } catch (e) { console.log(e); diff --git a/javascript/posts/delete_tweet.js b/javascript/posts/delete_tweet.js deleted file mode 100644 index ea6bfbd..0000000 --- a/javascript/posts/delete_tweet.js +++ /dev/null @@ -1,142 +0,0 @@ -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to replace your-tweet-id with the id of the Tweet you wish to delete. -const id = "your-tweet-id"; - -const endpointURL = `https://api.x.com/2/tweets/${id}`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "DELETE", - }, - token - ) - ); - - const req = await got.delete(endpointURL, { - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2DeleteTweetJS", - "content-type": "application/json" - accept: "application/json", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/full-archive-search.js b/javascript/posts/full-archive-search.js deleted file mode 100644 index c76d67e..0000000 --- a/javascript/posts/full-archive-search.js +++ /dev/null @@ -1,51 +0,0 @@ -// Search for public Tweets across the whole Twitter archive -// https://developer.twitter.com/en/docs/twitter-api/tweets/search/quick-start/full-archive-search - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const endpointUrl = 'https://api.x.com/2/tweets/search/all' - -async function getRequest() { - - // These are the parameters for the API request - // specify Tweet IDs to fetch, and any additional fields that are required - // by default, only the Tweet ID and text are returned - const params = { - 'query': 'from:twitterdev -is:retweet', - 'tweet.fields': 'author_id' - } - - const res = await needle('get', endpointUrl, params, { - headers: { - "User-Agent": "v2FullArchiveJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/full_archive_tweet_counts.js b/javascript/posts/full_archive_tweet_counts.js deleted file mode 100644 index 8ac536f..0000000 --- a/javascript/posts/full_archive_tweet_counts.js +++ /dev/null @@ -1,51 +0,0 @@ -// Search for public Tweets across the whole Twitter archive -// https://developer.twitter.com/en/docs/twitter-api/tweets/search/quick-start/full-archive-search - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const endpointUrl = 'https://api.x.com/2/tweets/counts/all' - -async function getRequest() { - - // Edit query parameters below and specify a search query - // optional params: start_time,end_time,since_id,until_id,next_token,granularity - const params = { - 'query': 'from:twitterdev', - 'granularity': 'day', - 'start_time': '2021-01-01T00:00:00Z' - } - - const res = await needle('get', endpointUrl, params, { - headers: { - "User-Agent": "v2FullArchiveTweetCountsJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/get_liking_users.js b/javascript/posts/get_liking_users.js new file mode 100644 index 0000000..c0e2866 --- /dev/null +++ b/javascript/posts/get_liking_users.js @@ -0,0 +1,106 @@ +// Get liking users for a post using OAuth 2.0 to authorize the user +// https://developer.twitter.com/en/docs/twitter-api/tweets/likes/api-reference/get-tweets-id-liking_users +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// You can replace the ID given with the Post ID you wish to get liking users for. +// You can find an ID by using the Post lookup endpoint +const id = "1354143047324299264"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'like.read', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // These are the parameters for the API request + // by default, only the Post ID and text are returned + const response = await client.posts.getLikingUsers(id, { + tweetFields: ['lang', 'author_id'], // Edit optional query parameters here + userFields: ['created_at'] // Edit optional query parameters here + }); + + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/posts/get_post_counts_all.js b/javascript/posts/get_post_counts_all.js new file mode 100644 index 0000000..4f9bbe2 --- /dev/null +++ b/javascript/posts/get_post_counts_all.js @@ -0,0 +1,30 @@ +// Search for public posts across the whole Twitter archive +// https://developer.twitter.com/en/docs/twitter-api/tweets/search/quick-start/full-archive-search + +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +(async () => { + try { + // Edit query parameters below and specify a search query + // optional params: start_time,end_time,since_id,until_id,next_token,granularity + const response = await client.posts.getCountsAll('from:xdevelopers', { + granularity: 'day', + startTime: '2021-01-01T00:00:00Z' + }); + + console.dir(response, { + depth: null + }); + + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); \ No newline at end of file diff --git a/javascript/posts/get_post_counts_recent.js b/javascript/posts/get_post_counts_recent.js new file mode 100644 index 0000000..0136d8e --- /dev/null +++ b/javascript/posts/get_post_counts_recent.js @@ -0,0 +1,30 @@ +// Search for posts within the past seven days +// https://developer.twitter.com/en/docs/twitter-api/tweets/search/quick-start/recent-search + +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +(async () => { + try { + // Edit query parameters below and specify a search query + // optional params: start_time,end_time,since_id,until_id,next_token,granularity + const response = await client.posts.getCountsRecent('from:xdevelopers', { + granularity: 'day' + }); + + console.dir(response, { + depth: null + }); + + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); + diff --git a/javascript/posts/get_posts_by_ids.js b/javascript/posts/get_posts_by_ids.js new file mode 100644 index 0000000..f86afdc --- /dev/null +++ b/javascript/posts/get_posts_by_ids.js @@ -0,0 +1,37 @@ +/** + * Post Lookup - X API v2 + * + * Endpoint: GET https://api.x.com/2/posts + * Docs: https://developer.x.com/en/docs/twitter-api/tweets/lookup/api-reference/get-tweets + * + * Authentication: Bearer Token (App-only) or OAuth (User Context) + * Required env vars: BEARER_TOKEN + */ + +const { Client } = require('@xdevplatform/xdk'); + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +// These are the parameters for the API request +// specify Post IDs to fetch, and any additional fields that are required +// by default, only the Post ID and text are returned +const postIDs = ['1278747501642657792', '1275828087666679809']; // Edit the Post IDs to look up + + +(async () => { + try { + // Post IDs to look up (comma-separated, up to 100) + const response = await client.posts.getByIds(postIDs, { + tweetFields: ['created_at', 'author_id', 'lang', 'source', 'public_metrics'], + userFields: ['created_at'], + expansions: ['author_id'] + }); + + console.dir(response, { depth: null }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/posts/get_posts_by_ids_user_context.js b/javascript/posts/get_posts_by_ids_user_context.js new file mode 100644 index 0000000..121aba9 --- /dev/null +++ b/javascript/posts/get_posts_by_ids_user_context.js @@ -0,0 +1,109 @@ +// Get Post objects by ID, using user authentication +// https://developer.twitter.com/en/docs/twitter-api/tweets/lookup/quick-start + +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// These are the parameters for the API request +// specify Post IDs to fetch, and any additional fields that are required +// by default, only the Post ID and text are returned +const postIDs = ['1278747501642657792', '1275828087666679809']; // Edit the Post IDs to look up + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.posts.getByIds(postIDs, { + tweetFields: ['lang', 'author_id'], + userFields: ['created_at'] + }); + + console.dir(response, { + depth: null + }); + + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); + diff --git a/javascript/posts/get_quoted_posts.js b/javascript/posts/get_quoted_posts.js new file mode 100644 index 0000000..8784a2a --- /dev/null +++ b/javascript/posts/get_quoted_posts.js @@ -0,0 +1,51 @@ +// Get Quote Posts by Post ID +// https://developer.twitter.com/en/docs/twitter-api/tweets/quote-tweets-lookup/quick-start + +const { Client, PostPaginator } = require('@xdevplatform/xdk'); + +const postId = '1980412193624785337'; + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const bearerToken = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: bearerToken }); + +const getQuotePosts = async () => { + console.log("Retrieving quote posts..."); + + // Use paginator for automatic pagination + const quotePosts = new PostPaginator( + async (token) => { + const res = await client.posts.getQuoted(postId, { + maxResults: 100, + paginationToken: token, + tweetFields: ['created_at'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; + } + ); + + // Fetch all pages + await quotePosts.fetchNext(); + while (!quotePosts.done) { + await quotePosts.fetchNext(); + } + + console.dir(quotePosts.posts, { + depth: null + }); + + console.log(`Got ${quotePosts.posts.length} quote posts for Post ID ${postId}!`); +} + +getQuotePosts().catch(err => { + console.error('Error:', err); + process.exit(-1); +}); + diff --git a/javascript/posts/get_reposted_by.js b/javascript/posts/get_reposted_by.js new file mode 100644 index 0000000..01306b8 --- /dev/null +++ b/javascript/posts/get_reposted_by.js @@ -0,0 +1,54 @@ +// Get Reposted By (Users who reposted) by Post ID +// https://developer.twitter.com/en/docs/twitter-api/tweets/retweets/api-reference/get-tweets-id-retweeted_by + +const { Client, UserPaginator } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const bearerToken = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: bearerToken }); + +// You can replace the ID given with the Post ID you wish to lookup reposting users for +// You can find an ID by using the Post lookup endpoint +const postId = "1980412193624785337"; + +const getRepostedBy = async () => { + console.log("Retrieving users who reposted..."); + + // Use paginator for automatic pagination + const repostedBy = new UserPaginator( + async (token) => { + const res = await client.posts.getRepostedBy(postId, { + maxResults: 100, + paginationToken: token, + tweetFields: ['lang', 'author_id'], + userFields: ['created_at'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; + } + ); + + // Fetch all pages + await repostedBy.fetchNext(); + while (!repostedBy.done) { + await repostedBy.fetchNext(); + } + + console.dir(repostedBy.users, { + depth: null + }); + + console.log(`Got ${repostedBy.users.length} users who reposted Post ID ${postId}!`); +} + +getRepostedBy().catch(err => { + console.error('Error:', err); + process.exit(-1); +}); + diff --git a/javascript/posts/get_tweets_with_bearer_token.js b/javascript/posts/get_tweets_with_bearer_token.js deleted file mode 100644 index fcdf694..0000000 --- a/javascript/posts/get_tweets_with_bearer_token.js +++ /dev/null @@ -1,53 +0,0 @@ -// Get Tweet objects by ID, using bearer token authentication -// https://developer.twitter.com/en/docs/twitter-api/tweets/lookup/quick-start - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const endpointURL = "https://api.x.com/2/tweets?ids="; - -async function getRequest() { - - // These are the parameters for the API request - // specify Tweet IDs to fetch, and any additional fields that are required - // by default, only the Tweet ID and text are returned - const params = { - "ids": "1278747501642657792,1255542774432063488", // Edit Tweet IDs to look up - "tweet.fields": "lang,author_id", // Edit optional query parameters here - "user.fields": "created_at" // Edit optional query parameters here - } - - // this is the HTTP header that adds bearer token authentication - const res = await needle('get', endpointURL, params, { - headers: { - "User-Agent": "v2TweetLookupJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/get_tweets_with_user_context.js b/javascript/posts/get_tweets_with_user_context.js deleted file mode 100644 index c769f6f..0000000 --- a/javascript/posts/get_tweets_with_user_context.js +++ /dev/null @@ -1,150 +0,0 @@ -// Get Tweet objects by ID, using user authentication -// https://developer.twitter.com/en/docs/twitter-api/tweets/lookup/quick-start - -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}) - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// These are the parameters for the API request -// specify Tweet IDs to fetch, and any additional fields that are required -// by default, only the Tweet ID and text are returned -const tweetIDs = '1278747501642657792,1275828087666679809'; // Edit the Tweet IDs to look up -const params = 'tweet.fields=lang,author_id&user.fields=created_at'; // Edit optional query parameters here - -const endpointURL = `https://api.x.com/2/tweets?ids=${tweetIDs}&${params}`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; - -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'GET' - }, token)); - - const req = await got(endpointURL, { - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2TweetLookupJS" - } - }); - - if (req.body) { - return JSON.parse(req.body); - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - try { - - // Get request token - const oAuthRequestToken = await requestToken(); - - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/like_a_tweet.js b/javascript/posts/like_a_tweet.js deleted file mode 100644 index 9ff9203..0000000 --- a/javascript/posts/like_a_tweet.js +++ /dev/null @@ -1,148 +0,0 @@ -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}); - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to replace your-user-id with your own user ID or one of an authenticating user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - -// You can replace Tweet ID given with the Tweet ID you wish to like. -// You can find a Tweet ID by using the Tweet lookup endpoint -const data = { - "tweet_id": "1354143047324299264" -}; - -const endpointURL = `https://api.x.com/2/users/${id}/likes`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'POST' - }, token)); - - const req = await got.post(endpointURL, { - json: data, - responseType: 'json', - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2LikeTweetJS", - 'content-type': "application/json", - 'accept': "application/json" - } - }); - if (req.body) { - return req.body; - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/liked_tweets.js b/javascript/posts/liked_tweets.js deleted file mode 100644 index ea65a93..0000000 --- a/javascript/posts/liked_tweets.js +++ /dev/null @@ -1,46 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; -const id = "your-user-id"; - -const endpointURL = `https://api.x.com/2/users/${id}/liked_tweets`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the Tweet ID and text are returned - const params = { - "tweet.fields": "lang,author_id", // Edit optional query parameters here - "user.fields": "created_at", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2LikedTweetsJS", - authorization: `Bearer ${token}` - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/liking_users.js b/javascript/posts/liking_users.js deleted file mode 100644 index 406025d..0000000 --- a/javascript/posts/liking_users.js +++ /dev/null @@ -1,49 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; - -// You can replace the ID given with the Tweet ID you wish to like. -// You can find an ID by using the Tweet lookup endpoint -const id = "1354143047324299264"; - -const endpointURL = `https://api.x.com/2/tweets/${id}/liking_users`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the Tweet ID and text are returned - const params = { - "tweet.fields": "lang,author_id", // Edit optional query parameters here - "user.fields": "created_at", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2LikingUsersJS", - authorization: `Bearer ${token}` - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/lookup.js b/javascript/posts/lookup.js deleted file mode 100644 index 51f7880..0000000 --- a/javascript/posts/lookup.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Post Lookup - X API v2 - * - * Endpoint: GET https://api.x.com/2/tweets - * Docs: https://developer.x.com/en/docs/twitter-api/tweets/lookup/api-reference/get-tweets - * - * Authentication: Bearer Token (App-only) or OAuth (User Context) - * Required env vars: BEARER_TOKEN - */ - -const needle = require('needle'); - -const token = process.env.BEARER_TOKEN; -const endpointURL = "https://api.x.com/2/tweets"; - -async function getRequest() { - // Post IDs to look up (comma-separated, up to 100) - const params = { - "ids": "1278747501642657792,1255542774432063488", - "tweet.fields": "created_at,author_id,lang,source,public_metrics", - "expansions": "author_id" - }; - - const res = await needle('get', endpointURL, params, { - headers: { - "User-Agent": "v2PostLookupJS", - "authorization": `Bearer ${token}` - } - }); - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - try { - const response = await getRequest(); - console.dir(response, { depth: null }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/quote_tweets.js b/javascript/posts/quote_tweets.js deleted file mode 100644 index ccc4230..0000000 --- a/javascript/posts/quote_tweets.js +++ /dev/null @@ -1,74 +0,0 @@ -// Get Quote Tweets by Tweet ID -// https://developer.twitter.com/en/docs/twitter-api/tweets/quote-tweets-lookup/quick-start - -const needle = require('needle'); - -const tweetId = 20; -const url = `https://api.x.com/2/tweets/${tweetId}/quote_tweets`; - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const bearerToken = process.env.BEARER_TOKEN; - -// this is the ID for @TwitterDev -const getQuoteTweets = async () => { - let quoteTweets = []; - let params = { - "max_results": 100, - "tweet.fields": "created_at" - } - - const options = { - headers: { - "User-Agent": "v2QuoteTweetsJS", - "authorization": `Bearer ${bearerToken}` - } - } - - let hasNextPage = true; - let nextToken = null; - console.log("Retrieving quote Tweets..."); - while (hasNextPage) { - let resp = await getPage(params, options, nextToken); - if (resp && resp.meta && resp.meta.result_count && resp.meta.result_count > 0) { - if (resp.data) { - quoteTweets.push.apply(quoteTweets, resp.data); - } - if (resp.meta.next_token) { - nextToken = resp.meta.next_token; - } else { - hasNextPage = false; - } - } else { - hasNextPage = false; - } - } - - console.dir(quoteTweets, { - depth: null - }); - - console.log(`Got ${quoteTweets.length} quote Tweets for Tweet ID ${tweetId}!`); - -} - -const getPage = async (params, options, nextToken) => { - if (nextToken) { - params.pagination_token = nextToken; - } - - try { - const resp = await needle('get', url, params, options); - - if (resp.statusCode != 200) { - console.log(`${resp.statusCode} ${resp.statusMessage}:\n${resp.body}`); - return; - } - return resp.body; - } catch (err) { - throw new Error(`Request failed: ${err}`); - } -} - -getQuoteTweets(); diff --git a/javascript/posts/recent_search.js b/javascript/posts/recent_search.js deleted file mode 100644 index 1d82ed4..0000000 --- a/javascript/posts/recent_search.js +++ /dev/null @@ -1,51 +0,0 @@ -// Search for Tweets within the past seven days -// https://developer.twitter.com/en/docs/twitter-api/tweets/search/quick-start/recent-search - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const endpointUrl = "https://api.x.com/2/tweets/search/recent"; - -async function getRequest() { - - // Edit query parameters below - // specify a search query, and any additional fields that are required - // by default, only the Tweet ID and text fields are returned - const params = { - 'query': 'from:twitterdev -is:retweet', - 'tweet.fields': 'author_id' - } - - const res = await needle('get', endpointUrl, params, { - headers: { - "User-Agent": "v2RecentSearchJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/recent_tweet_counts.js b/javascript/posts/recent_tweet_counts.js deleted file mode 100644 index 73b981f..0000000 --- a/javascript/posts/recent_tweet_counts.js +++ /dev/null @@ -1,50 +0,0 @@ -// Search for Tweets within the past seven days -// https://developer.twitter.com/en/docs/twitter-api/tweets/search/quick-start/recent-search - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const endpointUrl = "https://api.x.com/2/tweets/counts/recent"; - -async function getRequest() { - - // Edit query parameters below and specify a search query - // optional params: start_time,end_time,since_id,until_id,next_token,granularity - const params = { - 'query': 'from:twitterdev', - 'granularity': 'day' - } - - const res = await needle('get', endpointUrl, params, { - headers: { - "User-Agent": "v2RecentTweetCountsJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/retweet_a_tweet.js b/javascript/posts/retweet_a_tweet.js deleted file mode 100644 index 875b67b..0000000 --- a/javascript/posts/retweet_a_tweet.js +++ /dev/null @@ -1,148 +0,0 @@ -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}) - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - -// You can replace the given Tweet ID with your the Tweet ID you want to Retweet -// You can find a Tweet ID by using the Tweet lookup endpoint -const data = { - "tweet_id": "1412865600439738368" -} - -const endpointURL = `https://api.x.com/2/users/${id}/retweets`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'POST' - }, token)); - - const req = await got.post(endpointURL, { - json: data, - responseType: 'json', - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "vsRetweetTweetJS", - 'content-type': "application/json", - 'accept': "application/json" - } - }); - if (req.body) { - return req.body; - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/retweeted_by.js b/javascript/posts/retweeted_by.js deleted file mode 100644 index 3d25df8..0000000 --- a/javascript/posts/retweeted_by.js +++ /dev/null @@ -1,49 +0,0 @@ -const needle = require("needle"); -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' - -const token = process.env.BEARER_TOKEN; - -// You can replace the ID given with the Tweet ID you wish to lookup Retweeting users for -// You can find an ID by using the Tweet lookup endpoint -const id = "1354143047324299264"; - -const endpointURL = `https://api.x.com/2/tweets/${id}/retweeted_by`; - -async function getRequest() { - // These are the parameters for the API request - // by default, only the Tweet ID and text are returned - const params = { - "tweet.fields": "lang,author_id", // Edit optional query parameters here - "user.fields": "created_at", // Edit optional query parameters here - }; - - // this is the HTTP header that adds bearer token authentication - const res = await needle("get", endpointURL, params, { - headers: { - "User-Agent": "v2RetweetedByUsersJS", - authorization: `Bearer ${token}` - }, - }); - - if (res.body) { - return res.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/search_all.js b/javascript/posts/search_all.js new file mode 100644 index 0000000..e4ef515 --- /dev/null +++ b/javascript/posts/search_all.js @@ -0,0 +1,50 @@ +// Search for public posts across the whole Twitter archive +// https://developer.twitter.com/en/docs/twitter-api/tweets/search/quick-start/full-archive-search + +const { Client, PostPaginator } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const bearerToken = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: bearerToken }); + +const query = 'from:xdevelopers'; + +const searchAll = async () => { + console.log("Searching full archive..."); + + // Use paginator for automatic pagination + const searchResults = new PostPaginator( + async (token) => { + const res = await client.posts.searchAll(query, { + maxResults: 100, + nextToken: token, + tweetFields: ['author_id'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; + } + ); + + // Fetch all pages + await searchResults.fetchNext(); + while (!searchResults.done) { + await searchResults.fetchNext(); + } + + console.dir(searchResults.posts, { + depth: null + }); + + console.log(`Got ${searchResults.posts.length} posts for query: ${query}`); +} + +searchAll().catch(err => { + console.error('Error:', err); + process.exit(-1); +}); diff --git a/javascript/posts/search_recent.js b/javascript/posts/search_recent.js index 1315dc2..7b2fc7c 100644 --- a/javascript/posts/search_recent.js +++ b/javascript/posts/search_recent.js @@ -1,49 +1,58 @@ /** * Recent Search - X API v2 * - * Endpoint: GET https://api.x.com/2/tweets/search/recent + * Endpoint: GET https://api.x.com/2/posts/search/recent * Docs: https://developer.x.com/en/docs/twitter-api/tweets/search/api-reference/get-tweets-search-recent * * Authentication: Bearer Token (App-only) * Required env vars: BEARER_TOKEN * * Note: Returns posts from the last 7 days. + * This example demonstrates automatic pagination using PostPaginator + * to fetch all pages of results. */ -const needle = require('needle'); +const { Client, PostPaginator } = require('@xdevplatform/xdk'); -const token = process.env.BEARER_TOKEN; -const endpointUrl = "https://api.x.com/2/tweets/search/recent"; +const bearerToken = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: bearerToken }); -async function getRequest() { - // Edit query parameters below - // By default, only the post ID and text fields are returned - const params = { - 'query': 'from:XDevelopers -is:retweet', - 'tweet.fields': 'author_id,created_at' - }; +const query = 'from:x -is:retweet'; - const res = await needle('get', endpointUrl, params, { - headers: { - "User-Agent": "v2RecentSearchJS", - "authorization": `Bearer ${token}` +const searchRecent = async () => { + console.log("Searching recent posts..."); + + // Use paginator for automatic pagination + const searchResults = new PostPaginator( + async (token) => { + const res = await client.posts.searchRecent(query, { + maxResults: 100, + nextToken: token, + tweetFields: ['author_id', 'created_at'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; } - }); + ); - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); + // Fetch all pages + await searchResults.fetchNext(); + while (!searchResults.done) { + await searchResults.fetchNext(); } + + console.dir(searchResults.posts, { + depth: null + }); + + console.log(`Got ${searchResults.posts.length} posts for query: ${query}`); } -(async () => { - try { - const response = await getRequest(); - console.dir(response, { depth: null }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); +searchRecent().catch(err => { + console.error('Error:', err); + process.exit(-1); +}); diff --git a/javascript/posts/unblock_a_user.js b/javascript/posts/unblock_a_user.js deleted file mode 100644 index d8d5081..0000000 --- a/javascript/posts/unblock_a_user.js +++ /dev/null @@ -1,149 +0,0 @@ -// Unblock a user, using user authentication -// https://developer.twitter.com/en/docs/twitter-api/users/blocks/quick-start -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}) - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const source_user_id = "your-user-id"; - - -// Be sure to add replace the id-to-unblock with the user id of the you wish to unblock. -// You can find a user ID by using the user lookup endpoint -const target_user_id = "id-to-unblock" - -const endpointURL = `https://api.x.com/2/users/${source_user_id}/blocking/${target_user_id}`; - - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'DELETE' - }, token)); - - const req = await got.post(endpointURL, { - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2UnblockUserJS" - } - }); - if (req.body) { - return JSON.parse(req.body); - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); - - -// Note: If you were following the user you blocked, you have removed your follow and will have to refollow the user, even if you did unblock the user. diff --git a/javascript/posts/undo_a_retweet.js b/javascript/posts/undo_a_retweet.js deleted file mode 100644 index 1d0029f..0000000 --- a/javascript/posts/undo_a_retweet.js +++ /dev/null @@ -1,145 +0,0 @@ -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}); - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to replace your-user-id with your own user ID or one of an authenticating user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - - -// You can replace the given Tweet ID with your the Tweet ID you want to Retweet -// You can find a Tweet ID by using the Tweet lookup endpoint -const source_tweet_id = "1354143047324299264"; - -const endpointURL = `https://api.x.com/2/users/${id}/retweets/${source_tweet_id}`; - - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'DELETE' - }, token)); - - const req = await got.delete(endpointURL, { - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2UndoRetweetTweetJS" - } - }); - - if (req.body) { - return JSON.parse(req.body); - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/posts/unlike_a_tweet.js b/javascript/posts/unlike_a_tweet.js deleted file mode 100644 index f7c5905..0000000 --- a/javascript/posts/unlike_a_tweet.js +++ /dev/null @@ -1,145 +0,0 @@ -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}); - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to replace your-user-id with your own user ID or one of an authenticating user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - - -// You can replace Tweet ID given with the Tweet ID you wish to like. -// You can find a Tweet ID by using the Tweet lookup endpoint -const tweet_id = "1354143047324299264"; - -const endpointURL = `https://api.x.com/2/users/${id}/likes/${tweet_id}`; - - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'DELETE' - }, token)); - - const req = await got.delete(endpointURL, { - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2UnlikeTweetJS" - } - }); - - if (req.body) { - return JSON.parse(req.body); - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/spaces/get_spaces_by_ids.js b/javascript/spaces/get_spaces_by_ids.js new file mode 100644 index 0000000..671c388 --- /dev/null +++ b/javascript/spaces/get_spaces_by_ids.js @@ -0,0 +1,31 @@ +/** + * Spaces Lookup - X API v2 + * + * Endpoint: GET https://api.x.com/2/spaces + * Docs: https://developer.x.com/en/docs/twitter-api/spaces/lookup/api-reference/get-spaces + * + * Authentication: Bearer Token (App-only) or OAuth (User Context) + * Required env vars: BEARER_TOKEN + */ + +const { Client } = require('@xdevplatform/xdk'); + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +const spaceIds = ['1DXxyRYNejbKM']; + +(async () => { + try { + // Replace with Space IDs you want to look up + const response = await client.spaces.getByIds(spaceIds, { + spaceFields: ['host_ids', 'created_at', 'creator_id', 'participant_count', 'title', 'state'] + }); + + console.dir(response, { depth: null }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/spaces/lookup.js b/javascript/spaces/lookup.js deleted file mode 100644 index 6d8b2a6..0000000 --- a/javascript/spaces/lookup.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Spaces Lookup - X API v2 - * - * Endpoint: GET https://api.x.com/2/spaces - * Docs: https://developer.x.com/en/docs/twitter-api/spaces/lookup/api-reference/get-spaces - * - * Authentication: Bearer Token (App-only) or OAuth (User Context) - * Required env vars: BEARER_TOKEN - */ - -const needle = require('needle'); - -const token = process.env.BEARER_TOKEN; -const endpointURL = "https://api.x.com/2/spaces"; - -async function getRequest() { - const params = { - "ids": "1DXxyRYNejbKM", - "space.fields": "host_ids,created_at,creator_id,participant_count,title,state" - }; - - const res = await needle('get', endpointURL, params, { - headers: { - "User-Agent": "v2SpacesLookupJS", - "authorization": `Bearer ${token}` - } - }); - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - try { - const response = await getRequest(); - console.dir(response, { depth: null }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/spaces/search_spaces.js b/javascript/spaces/search_spaces.js index eb58ed3..33761c8 100644 --- a/javascript/spaces/search_spaces.js +++ b/javascript/spaces/search_spaces.js @@ -1,44 +1,25 @@ // Lookup Spaces by ID // https://developer.twitter.com/en/docs/twitter-api/spaces/lookup -const needle = require('needle'); +const { Client } = require('@xdevplatform/xdk'); // The code below sets the bearer token from your environment variables // To set environment variables on macOS or Linux, run the export command below from the terminal: // export BEARER_TOKEN='YOUR-TOKEN' const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); -const endpointUrl = `https://api.x.com/2/spaces/search`; - -async function getRequest() { - - // Edit query parameters below and specify a search query - // optional params: host_ids,conversation_controls,created_at,creator_id,id,invited_user_ids,is_ticketed,lang,media_key,participants,scheduled_start,speaker_ids,started_at,state,title,updated_at - const params = { - 'query': 'NBA', // Replace the value with your search term - 'space.fields': 'title,created_at', - 'expansions': 'creator_id' - } - - const res = await needle('get', endpointUrl, params, { - headers: { - "User-Agent": "v2SpacesSearchJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} +const query = 'NBA'; (async () => { - try { - // Make request - const response = await getRequest(); + // Edit query parameters below and specify a search query + // optional params: host_ids,conversation_controls,created_at,creator_id,id,invited_user_ids,is_ticketed,lang,media_key,participants,scheduled_start,speaker_ids,started_at,state,title,updated_at + const response = await client.spaces.search(query, { + spaceFields: ['title', 'created_at'], + expansions: ['creator_id'] + }); + console.dir(response, { depth: null }); diff --git a/javascript/spaces/spaces_lookup.js b/javascript/spaces/spaces_lookup.js deleted file mode 100644 index 73b981f..0000000 --- a/javascript/spaces/spaces_lookup.js +++ /dev/null @@ -1,50 +0,0 @@ -// Search for Tweets within the past seven days -// https://developer.twitter.com/en/docs/twitter-api/tweets/search/quick-start/recent-search - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const endpointUrl = "https://api.x.com/2/tweets/counts/recent"; - -async function getRequest() { - - // Edit query parameters below and specify a search query - // optional params: start_time,end_time,since_id,until_id,next_token,granularity - const params = { - 'query': 'from:twitterdev', - 'granularity': 'day' - } - - const res = await needle('get', endpointUrl, params, { - headers: { - "User-Agent": "v2RecentTweetCountsJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/streams/filtered_stream.js b/javascript/streams/filtered_stream.js deleted file mode 100644 index 3926e98..0000000 --- a/javascript/streams/filtered_stream.js +++ /dev/null @@ -1,160 +0,0 @@ -// Open a realtime stream of Tweets, filtered according to rules -// https://developer.twitter.com/en/docs/twitter-api/tweets/filtered-stream/quick-start - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const rulesURL = 'https://api.x.com/2/tweets/search/stream/rules'; -const streamURL = 'https://api.x.com/2/tweets/search/stream'; - -// this sets up two rules - the value is the search terms to match on, and the tag is an identifier that -// will be applied to the Tweets return to show which rule they matched -// with a standard project with Basic Access, you can add up to 25 concurrent rules to your stream, and -// each rule can be up to 512 characters long - -// Edit rules as desired below -const rules = [{ - 'value': 'dog has:images -is:retweet', - 'tag': 'dog pictures' - }, - { - 'value': 'cat has:images -grumpy', - 'tag': 'cat pictures' - }, -]; - -async function getAllRules() { - - const response = await needle('get', rulesURL, { - headers: { - "authorization": `Bearer ${token}` - } - }) - - if (response.statusCode !== 200) { - console.log("Error:", response.statusMessage, response.statusCode) - throw new Error(response.body); - } - - return (response.body); -} - -async function deleteAllRules(rules) { - - if (!Array.isArray(rules.data)) { - return null; - } - - const ids = rules.data.map(rule => rule.id); - - const data = { - "delete": { - "ids": ids - } - } - - const response = await needle('post', rulesURL, data, { - headers: { - "content-type": "application/json", - "authorization": `Bearer ${token}` - } - }) - - if (response.statusCode !== 200) { - throw new Error(response.body); - } - - return (response.body); - -} - -async function setRules() { - - const data = { - "add": rules - } - - const response = await needle('post', rulesURL, data, { - headers: { - "content-type": "application/json", - "authorization": `Bearer ${token}` - } - }) - - if (response.statusCode !== 201) { - throw new Error(response.body); - } - - return (response.body); - -} - -function streamConnect(retryAttempt) { - - const stream = needle.get(streamURL, { - headers: { - "User-Agent": "v2FilterStreamJS", - "Authorization": `Bearer ${token}` - }, - timeout: 20000 - }); - - stream.on('data', data => { - try { - const json = JSON.parse(data); - console.log(json); - // A successful connection resets retry count. - retryAttempt = 0; - } catch (e) { - if (data.detail === "This stream is currently at the maximum allowed connection limit.") { - console.log(data.detail) - process.exit(1) - } else { - // Keep alive signal received. Do nothing. - } - } - }).on('err', error => { - if (error.code !== 'ECONNRESET') { - console.log(error.code); - process.exit(1); - } else { - // This reconnection logic will attempt to reconnect when a disconnection is detected. - // To avoid rate limits, this logic implements exponential backoff, so the wait time - // will increase if the client cannot reconnect to the stream. - setTimeout(() => { - console.warn("A connection error occurred. Reconnecting...") - streamConnect(++retryAttempt); - }, 2 ** retryAttempt) - } - }); - - return stream; - -} - - -(async () => { - let currentRules; - - try { - // Gets the complete list of rules currently applied to the stream - currentRules = await getAllRules(); - - // Delete all rules. Comment the line below if you want to keep your existing rules. - await deleteAllRules(currentRules); - - // Add rules to the stream. Comment the line below if you don't want to add new rules. - await setRules(); - - } catch (e) { - console.error(e); - process.exit(1); - } - - // Listen to the stream. - streamConnect(0); -})(); diff --git a/javascript/streams/sampled_stream.js b/javascript/streams/sampled_stream.js deleted file mode 100644 index 533f747..0000000 --- a/javascript/streams/sampled_stream.js +++ /dev/null @@ -1,60 +0,0 @@ -// Open a live stream of roughly 1% random sample of publicly available Tweets -// https://developer.twitter.com/en/docs/twitter-api/tweets/volume-streams/quick-start - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const streamURL = 'https://api.x.com/2/tweets/sample/stream'; - -function streamConnect(retryAttempt) { - - const stream = needle.get(streamURL, { - headers: { - "User-Agent": "v2SampleStreamJS", - "Authorization": `Bearer ${token}` - }, - timeout: 20000 - }); - - stream.on('data', data => { - try { - const json = JSON.parse(data); - console.log(json); - // A successful connection resets retry count. - retryAttempt = 0; - } catch (e) { - // Catches error in case of 401 unauthorized error status. - if (data.status === 401) { - console.log(data); - process.exit(1); - } else if (data.detail === "This stream is currently at the maximum allowed connection limit.") { - console.log(data.detail) - process.exit(1) - } else { - // Keep alive signal received. Do nothing. - } - } - }).on('err', error => { - if (error.code !== 'ECONNRESET') { - console.log(error.code); - process.exit(1); - } else { - // This reconnection logic will attempt to reconnect when a disconnection is detected. - // To avoid rate limits, this logic implements exponential backoff, so the wait time - // will increase if the client cannot reconnect to the stream. - setTimeout(() => { - console.warn("A connection error occurred. Reconnecting...") - streamConnect(++retryAttempt); - }, 2 ** retryAttempt); - } - }); - return stream; -} - -(async () => { - streamConnect(0) -})(); diff --git a/javascript/streams/stream_posts_filtered.js b/javascript/streams/stream_posts_filtered.js new file mode 100644 index 0000000..4966722 --- /dev/null +++ b/javascript/streams/stream_posts_filtered.js @@ -0,0 +1,72 @@ +// Open a realtime stream of posts, filtered according to rules +// https://developer.twitter.com/en/docs/twitter-api/tweets/filtered-stream/quick-start + +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +// this sets up two rules - the value is the search terms to match on, and the tag is an identifier that +// will be applied to the posts returned to show which rule they matched +// with a standard project with Basic Access, you can add up to 25 concurrent rules to your stream, and +// each rule can be up to 512 characters long + +// Edit rules as desired below +const rules = [{ + value: 'dog has:images -is:retweet', + tag: 'dog pictures' + }, + { + value: 'cat has:images -grumpy', + tag: 'cat pictures' + }, +]; + +(async () => { + try { + // Gets the complete list of rules currently applied to the stream + const currentRules = await client.stream.getRules(); + + // Delete all rules. Comment the line below if you want to keep your existing rules. + if (currentRules.data && currentRules.data.length > 0) { + const ids = currentRules.data.map(rule => rule.id); + await client.stream.updateRules({ delete: { ids: ids } }); + } + + // Add rules to the stream. Comment the line below if you don't want to add new rules. + await client.stream.updateRules({ add: rules }); + + // Listen to the stream + const stream = await client.stream.posts({ + tweetFields: ['id', 'text', 'created_at'] + }); + + stream.on('data', (event) => { + // event is the parsed JSON line (data/includes/matching_rules) + console.log('New data:', event); + }); + + stream.on('error', (e) => { + console.error('Stream error:', e); + if (e.detail === "This stream is currently at the maximum allowed connection limit.") { + console.log(e.detail); + process.exit(1); + } + }); + + stream.on('keepAlive', () => { + // heartbeat event - keep alive signal received + }); + + stream.on('close', () => { + console.log('Stream closed'); + }); + + } catch (e) { + console.error(e); + process.exit(1); + } +})(); diff --git a/javascript/streams/stream_posts_sample.js b/javascript/streams/stream_posts_sample.js new file mode 100644 index 0000000..402c47a --- /dev/null +++ b/javascript/streams/stream_posts_sample.js @@ -0,0 +1,47 @@ +// Open a live stream of roughly 1% random sample of publicly available posts +// https://developer.twitter.com/en/docs/twitter-api/tweets/volume-streams/quick-start + +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +(async () => { + try { + // 1% sampled public posts + const stream = await client.stream.postsSample({ + tweetFields: ['id', 'text', 'created_at'] + }); + + // Listen to events + stream.on('data', (event) => { + // event is the parsed JSON line (data/includes/matching_rules) + console.log('New data:', event); + }); + + stream.on('error', (e) => { + console.error('Stream error:', e); + if (e.status === 401) { + console.log('Unauthorized'); + process.exit(1); + } else if (e.detail === "This stream is currently at the maximum allowed connection limit.") { + console.log(e.detail); + process.exit(1); + } + }); + + stream.on('keepAlive', () => { + // heartbeat event - keep alive signal received + }); + + stream.on('close', () => { + console.log('Stream closed'); + }); + } catch (e) { + console.error('Error:', e); + process.exit(1); + } +})(); diff --git a/javascript/timelines/reverse-chron-home-timeline-js-sdk.js b/javascript/timelines/reverse-chron-home-timeline-js-sdk.js deleted file mode 100644 index b0b4cab..0000000 --- a/javascript/timelines/reverse-chron-home-timeline-js-sdk.js +++ /dev/null @@ -1,92 +0,0 @@ -const { Client, auth } = require("twitter-api-sdk"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -//Helper function to parse callback -const getQueryStringParams = (query) => { - return query - ? (/^[?#]/.test(query) ? query.slice(1) : query) - .split(/[\?\&]/) - .reduce((params, param) => { - let [key, value] = param.split("="); - params[key] = value - ? decodeURIComponent(value.replace(/\+/g, " ")) - : ""; - return params; - }, {}) - : {}; -}; - -//Helper terminal input function -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CLIENT_ID='YOUR-CLIENT-ID' -// export CLIENET_SECRET='YOUR-CLIENT-SECRET' -const CLIENT_ID = process.env.CLIENT_ID; -const CLIENT_SECRET = process.env.CLIENT_SECRET; - -// Optional parameters for additional payload data -const params = { - expansions: "author_id", - "user.fields": ["username", "created_at"], - "tweet.fields": ["geo", "entities", "context_annotations"], -}; - -(async () => { - const authClient = new auth.OAuth2User({ - client_id: CLIENT_ID, - client_secret: CLIENT_SECRET, - callback: "https://www.example.com/oauth", - scopes: ["tweet.read", "users.read"], - }); - - const client = new Client(authClient); - const STATE = "my-state"; - - //Get authorization - const authUrl = authClient.generateAuthURL({ - state: STATE, - code_challenge: "challenge", - }); - - console.log(`Please go here and authorize:`, authUrl); - - //Input users callback url in termnial - const redirectCallback = await input("Paste the redirected callback here: "); - - try { - //Parse callback - const { state, code } = getQueryStringParams(redirectCallback); - if (state !== STATE) { - console.log("State isn't matching"); - } - //Gets access token - await authClient.requestAccessToken(code); - - //Get the user ID - const { - data: { id }, - } = await client.users.findMyUser(); - - //Makes api call - const getUsersTimeline = await client.tweets.usersIdTimeline(id, params); - console.dir(getUsersTimeline, { - depth: null, - }); - process.exit(); - } catch (error) { - console.log(error); - } -})(); diff --git a/javascript/timelines/reverse-chron-home-timeline.js b/javascript/timelines/reverse-chron-home-timeline.js deleted file mode 100644 index 51d4dbd..0000000 --- a/javascript/timelines/reverse-chron-home-timeline.js +++ /dev/null @@ -1,142 +0,0 @@ -// Retrieve accounts muted by authenticated user -// https://developer.twitter.com/en/docs/twitter-api/users/mutes/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; -const endpointURL = `https://api.x.com/2/users/${id}/timelines/reverse_chronological`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "GET", - }, - token - ) - ); - - const req = await got.get(endpointURL, { - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2ReverseChronHomeTimelinesJS", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/timelines/user_mentions.js b/javascript/timelines/user_mentions.js deleted file mode 100644 index 98a4fd7..0000000 --- a/javascript/timelines/user_mentions.js +++ /dev/null @@ -1,74 +0,0 @@ -// Get User mentions timeline by user ID -// https://developer.twitter.com/en/docs/twitter-api/tweets/timelines/quick-start - -const needle = require('needle'); - -const userId = 2244994945; -const url = `https://api.x.com/2/users/${userId}/mentions`; - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const bearerToken = process.env.BEARER_TOKEN; - -// this is the ID for @TwitterDev -const getUserMentions = async () => { - let userMentions = []; - let params = { - "max_results": 100, - "tweet.fields": "created_at" - } - - const options = { - headers: { - "User-Agent": "v2UserMentionssJS", - "authorization": `Bearer ${bearerToken}` - } - } - - let hasNextPage = true; - let nextToken = null; - console.log("Retrieving mentions..."); - while (hasNextPage) { - let resp = await getPage(params, options, nextToken); - if (resp && resp.meta && resp.meta.result_count && resp.meta.result_count > 0) { - if (resp.data) { - userMentions.push.apply(userMentions, resp.data); - } - if (resp.meta.next_token) { - nextToken = resp.meta.next_token; - } else { - hasNextPage = false; - } - } else { - hasNextPage = false; - } - } - - console.dir(userMentions, { - depth: null - }); - - console.log(`Got ${userMentions.length} mentions for user ID ${userId}!`); - -} - -const getPage = async (params, options, nextToken) => { - if (nextToken) { - params.pagination_token = nextToken; - } - - try { - const resp = await needle('get', url, params, options); - - if (resp.statusCode != 200) { - console.log(`${resp.statusCode} ${resp.statusMessage}:\n${resp.body}`); - return; - } - return resp.body; - } catch (err) { - throw new Error(`Request failed: ${err}`); - } -} - -getUserMentions(); diff --git a/javascript/timelines/user_posts.js b/javascript/timelines/user_posts.js deleted file mode 100644 index 100f443..0000000 --- a/javascript/timelines/user_posts.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * User Posts Timeline - X API v2 - * - * Endpoint: GET https://api.x.com/2/users/:id/tweets - * Docs: https://developer.x.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-tweets - * - * Authentication: Bearer Token (App-only) or OAuth (User Context) - * Required env vars: BEARER_TOKEN - */ - -const needle = require('needle'); - -const token = process.env.BEARER_TOKEN; - -// Replace with the user ID you want to get posts for -const userId = "2244994945"; -const endpointURL = `https://api.x.com/2/users/${userId}/tweets`; - -async function getRequest() { - const params = { - "tweet.fields": "created_at,public_metrics", - "max_results": 10 - }; - - const res = await needle('get', endpointURL, params, { - headers: { - "User-Agent": "v2UserPostsJS", - "authorization": `Bearer ${token}` - } - }); - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - try { - const response = await getRequest(); - console.dir(response, { depth: null }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/timelines/user_tweets.js b/javascript/timelines/user_tweets.js deleted file mode 100644 index 2576822..0000000 --- a/javascript/timelines/user_tweets.js +++ /dev/null @@ -1,79 +0,0 @@ -// Get User Tweet timeline by user ID -// https://developer.twitter.com/en/docs/twitter-api/tweets/timelines/quick-start - -const needle = require('needle'); - -// this is the ID for @TwitterDev -const userId = "2244994945"; -const url = `https://api.x.com/2/users/${userId}/tweets`; - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const bearerToken = process.env.BEARER_TOKEN; - -const getUserTweets = async () => { - let userTweets = []; - - // we request the author_id expansion so that we can print out the user name later - let params = { - "max_results": 100, - "tweet.fields": "created_at", - "expansions": "author_id" - } - - const options = { - headers: { - "User-Agent": "v2UserTweetsJS", - "authorization": `Bearer ${bearerToken}` - } - } - - let hasNextPage = true; - let nextToken = null; - let userName; - console.log("Retrieving Tweets..."); - - while (hasNextPage) { - let resp = await getPage(params, options, nextToken); - if (resp && resp.meta && resp.meta.result_count && resp.meta.result_count > 0) { - userName = resp.includes.users[0].username; - if (resp.data) { - userTweets.push.apply(userTweets, resp.data); - } - if (resp.meta.next_token) { - nextToken = resp.meta.next_token; - } else { - hasNextPage = false; - } - } else { - hasNextPage = false; - } - } - - console.dir(userTweets, { - depth: null - }); - console.log(`Got ${userTweets.length} Tweets from ${userName} (user ID ${userId})!`); - -} - -const getPage = async (params, options, nextToken) => { - if (nextToken) { - params.pagination_token = nextToken; - } - - try { - const resp = await needle('get', url, params, options); - - if (resp.statusCode != 200) { - console.log(`${resp.statusCode} ${resp.statusMessage}:\n${resp.body}`); - return; - } - return resp.body; - } catch (err) { - throw new Error(`Request failed: ${err}`); - } -} - -getUserTweets(); diff --git a/javascript/usage/get_usage.js b/javascript/usage/get_usage.js new file mode 100644 index 0000000..e350512 --- /dev/null +++ b/javascript/usage/get_usage.js @@ -0,0 +1,27 @@ +// Get Posts Usage +// https://developer.twitter.com/en/docs/twitter-api/usage/tweets + +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +(async () => { + try { + // Make request + const response = await client.usage.get(); + + console.dir(response, { + depth: null + }); + + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); + diff --git a/javascript/usage/get_usage_tweets.js b/javascript/usage/get_usage_tweets.js deleted file mode 100644 index 31ec211..0000000 --- a/javascript/usage/get_usage_tweets.js +++ /dev/null @@ -1,44 +0,0 @@ -// Get Tweets Usage -// https://developer.twitter.com/en/docs/twitter-api/usage/tweets - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const endpointURL = "https://api.x.com/2/usage/tweets"; - -async function getRequest() { - - // this is the HTTP header that adds bearer token authentication - const res = await needle('get', endpointURL, { - headers: { - "User-Agent": "v2UsageTweetsJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/users/block/get_blocking.js b/javascript/users/block/get_blocking.js new file mode 100644 index 0000000..4c472fb --- /dev/null +++ b/javascript/users/block/get_blocking.js @@ -0,0 +1,101 @@ +// Block a user, using user authentication +// https://developer.twitter.com/en/docs/twitter-api/users/blocks/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write', 'offline.access', 'block.read'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.getBlocking(userId); + console.dir(response, { + depth: null + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/bookmark/create_bookmark.js b/javascript/users/bookmark/create_bookmark.js new file mode 100644 index 0000000..1b7ee7e --- /dev/null +++ b/javascript/users/bookmark/create_bookmark.js @@ -0,0 +1,107 @@ +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +//Helper function to parse callback +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +//Helper terminal input function +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const CLIENT_ID = process.env.CLIENT_ID; +const CLIENT_SECRET = process.env.CLIENT_SECRET; + +// Include the ID of the Post you wish to bookmark +const tweetId = "post-id"; // Replace with the ID of the Post you wish to bookmark + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'bookmark.write'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const STATE = "my-state"; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(STATE); + console.log(`Please go here and authorize:`, authUrl); + + //Input users callback url in terminal + const redirectCallback = await input("Paste the redirected callback here: "); + + //Parse callback + const { state, code } = getQueryStringParams(redirectCallback); + if (state !== STATE) { + console.log("State isn't matching"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + //Get the user ID + const meResponse = await client.users.getMe(); + const userId = meResponse.data?.id; + + if (!userId) { + throw new Error('Could not get user ID'); + } + + //Makes api call + const postBookmark = await client.users.createBookmark(userId, { tweet_id: tweetId }); + console.dir(postBookmark, { + depth: null, + }); + process.exit(); + } catch (error) { + console.log(error); + process.exit(-1); + } +})(); diff --git a/javascript/users/bookmark/delete_bookmark.js b/javascript/users/bookmark/delete_bookmark.js new file mode 100644 index 0000000..64c5ccf --- /dev/null +++ b/javascript/users/bookmark/delete_bookmark.js @@ -0,0 +1,107 @@ +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +//Helper function to parse callback +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +//Helper terminal input function +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const CLIENT_ID = process.env.CLIENT_ID; +const CLIENT_SECRET = process.env.CLIENT_SECRET; + +// Include the ID of the Post you wish to unbookmark +const tweetId = "1996314591996129694"; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'bookmark.write'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const STATE = "my-state"; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(STATE); + console.log(`Please go here and authorize:`, authUrl); + + //Input users callback url in terminal + const redirectCallback = await input("Paste the redirected callback here: "); + + //Parse callback + const { state, code } = getQueryStringParams(redirectCallback); + if (state !== STATE) { + console.log("State isn't matching"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + //Get the user ID + const meResponse = await client.users.getMe(); + const userId = meResponse.data?.id; + + if (!userId) { + throw new Error('Could not get user ID'); + } + + //Makes api call + const deleteBookmark = await client.users.deleteBookmark(userId, tweetId); + console.dir(deleteBookmark, { + depth: null, + }); + process.exit(); + } catch (error) { + console.log(error); + process.exit(-1); + } +})(); diff --git a/javascript/users/bookmark/get_bookmarks.js b/javascript/users/bookmark/get_bookmarks.js new file mode 100644 index 0000000..44b22a8 --- /dev/null +++ b/javascript/users/bookmark/get_bookmarks.js @@ -0,0 +1,111 @@ +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +//Helper function to parse callback +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +//Helper terminal input function +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const CLIENT_ID = process.env.CLIENT_ID; +const CLIENT_SECRET = process.env.CLIENT_SECRET; + +// Optional parameters for additional payload data +const params = { + expansions: ['author_id'], + userFields: ['username', 'created_at'], + tweetFields: ['geo', 'entities', 'context_annotations'] +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: CLIENT_ID, + clientSecret: CLIENT_SECRET, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'bookmark.read'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const STATE = "my-state"; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(STATE); + console.log(`Please go here and authorize:`, authUrl); + + //Input users callback url in terminal + const redirectCallback = await input("Paste the redirected callback here: "); + + //Parse callback + const { state, code } = getQueryStringParams(redirectCallback); + if (state !== STATE) { + console.log("State isn't matching"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + //Get the user ID + const meResponse = await client.users.getMe(); + const userId = meResponse.data?.id; + + if (!userId) { + throw new Error('Could not get user ID'); + } + + //Makes api call + const getBookmark = await client.users.getBookmarks(userId, params); + console.dir(getBookmark, { + depth: null, + }); + process.exit(); + } catch (error) { + console.log(error); + process.exit(-1); + } +})(); diff --git a/javascript/users/follow/get_followers.js b/javascript/users/follow/get_followers.js new file mode 100644 index 0000000..d9c6f6f --- /dev/null +++ b/javascript/users/follow/get_followers.js @@ -0,0 +1,44 @@ +// Fetch the followers of a user account, by ID +// https://developer.twitter.com/en/docs/twitter-api/users/follows/quick-start + +const { Client, UserPaginator } = require('@xdevplatform/xdk'); + +// this is the ID for @XDevelopers +const userId = '2244994945'; +const bearerToken = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: bearerToken }); + +const getFollowers = async () => { + console.log("Retrieving followers..."); + + // Use paginator for automatic pagination + const followers = new UserPaginator( + async (token) => { + const res = await client.users.getFollowers(userId, { + maxResults: 1000, + paginationToken: token, + userFields: ['created_at'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; + } + ); + + // Fetch all pages + await followers.fetchNext(); + while (!followers.done) { + await followers.fetchNext(); + } + + console.log(followers.users); + console.log(`Got ${followers.users.length} users.`); +} + +getFollowers().catch(err => { + console.error('Error:', err); + process.exit(-1); +}); diff --git a/javascript/users/follow/get_followers_paginated.js b/javascript/users/follow/get_followers_paginated.js new file mode 100644 index 0000000..abfa11b --- /dev/null +++ b/javascript/users/follow/get_followers_paginated.js @@ -0,0 +1,56 @@ +/** + * User Followers Lookup (Paginated) - X API v2 + * + * Endpoint: GET https://api.x.com/2/users/:id/followers + * Docs: https://developer.x.com/en/docs/twitter-api/users/follows/api-reference/get-users-id-followers + * + * Authentication: Bearer Token (App-only) or OAuth (User Context) + * Required env vars: BEARER_TOKEN + * + * This example demonstrates automatic pagination using UserPaginator + * to fetch all pages of results. For a simple single-request example, + * see followers_lookup.js + */ + +const { Client, UserPaginator } = require('@xdevplatform/xdk'); + +// this is the ID for @XDevelopers +const userId = '2244994945'; +const bearerToken = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: bearerToken }); + +const getFollowers = async () => { + console.log("Retrieving followers..."); + + // Use paginator for automatic pagination + const followers = new UserPaginator( + async (token) => { + const res = await client.users.getFollowers(userId, { + maxResults: 1000, + paginationToken: token, + userFields: ['created_at'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; + } + ); + + // Fetch all pages + await followers.fetchNext(); + while (!followers.done) { + await followers.fetchNext(); + } + + console.log(followers.users); + console.log(`Got ${followers.users.length} users.`); +} + +getFollowers().catch(err => { + console.error('Error:', err); + process.exit(-1); +}); + diff --git a/javascript/users/follow/get_following_paginated.js b/javascript/users/follow/get_following_paginated.js new file mode 100644 index 0000000..069214d --- /dev/null +++ b/javascript/users/follow/get_following_paginated.js @@ -0,0 +1,55 @@ +/** + * User Following Lookup (Paginated) - X API v2 + * + * Endpoint: GET https://api.x.com/2/users/:id/following + * Docs: https://developer.x.com/en/docs/twitter-api/users/follows/api-reference/get-users-id-following + * + * Authentication: Bearer Token (App-only) or OAuth (User Context) + * Required env vars: BEARER_TOKEN + * + * This example demonstrates automatic pagination using UserPaginator + * to fetch all pages of results. + */ + +const { Client, UserPaginator } = require('@xdevplatform/xdk'); + +// this is the ID for @XDevelopers +const userId = '2244994945'; +const bearerToken = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: bearerToken }); + +const getFollowing = async () => { + console.log("Retrieving users this user is following..."); + + // Use paginator for automatic pagination + const following = new UserPaginator( + async (token) => { + const res = await client.users.getFollowing(userId, { + maxResults: 1000, + paginationToken: token, + userFields: ['created_at'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; + } + ); + + // Fetch all pages + await following.fetchNext(); + while (!following.done) { + await following.fetchNext(); + } + + console.log(following.users); + console.log(`Got ${following.users.length} users.`); +} + +getFollowing().catch(err => { + console.error('Error:', err); + process.exit(-1); +}); + diff --git a/javascript/users/followers.js b/javascript/users/followers.js deleted file mode 100644 index 7605b47..0000000 --- a/javascript/users/followers.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * User Followers Lookup - X API v2 - * - * Endpoint: GET https://api.x.com/2/users/:id/followers - * Docs: https://developer.x.com/en/docs/twitter-api/users/follows/api-reference/get-users-id-followers - * - * Authentication: Bearer Token (App-only) or OAuth (User Context) - * Required env vars: BEARER_TOKEN - */ - -const needle = require('needle'); - -const token = process.env.BEARER_TOKEN; - -// Replace with the user ID you want to get followers for -const userId = "2244994945"; -const endpointURL = `https://api.x.com/2/users/${userId}/followers`; - -async function getRequest() { - const params = { - "user.fields": "created_at,description", - "max_results": 100 - }; - - const res = await needle('get', endpointURL, params, { - headers: { - "User-Agent": "v2FollowersJS", - "authorization": `Bearer ${token}` - } - }); - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - try { - const response = await getRequest(); - console.dir(response, { depth: null }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/users/followers_lookup.js b/javascript/users/followers_lookup.js deleted file mode 100644 index cf93eb1..0000000 --- a/javascript/users/followers_lookup.js +++ /dev/null @@ -1,67 +0,0 @@ -// Fetch the followers of a user account, by ID -// https://developer.twitter.com/en/docs/twitter-api/users/follows/quick-start - -const needle = require('needle'); - -// this is the ID for @TwitterDev -const userId = 2244994945; -const url = `https://api.x.com/2/users/${userId}/followers`; -const bearerToken = process.env.BEARER_TOKEN; - -const getFollowers = async () => { - let users = []; - let params = { - "max_results": 1000, - "user.fields": "created_at" - } - - const options = { - headers: { - "User-Agent": "v2FollowersJS", - "authorization": `Bearer ${bearerToken}` - } - } - - let hasNextPage = true; - let nextToken = null; - console.log("Retrieving followers..."); - while (hasNextPage) { - let resp = await getPage(params, options, nextToken); - if (resp && resp.meta && resp.meta.result_count && resp.meta.result_count > 0) { - if (resp.data) { - users.push.apply(users, resp.data); - } - if (resp.meta.next_token) { - nextToken = resp.meta.next_token; - } else { - hasNextPage = false; - } - } else { - hasNextPage = false; - } - } - - console.log(users); - console.log(`Got ${users.length} users.`); - -} - -const getPage = async (params, options, nextToken) => { - if (nextToken) { - params.pagination_token = nextToken; - } - - try { - const resp = await needle('get', url, params, options); - - if (resp.statusCode != 200) { - console.log(`${resp.statusCode} ${resp.statusMessage}:\n${resp.body}`); - return; - } - return resp.body; - } catch (err) { - throw new Error(`Request failed: ${err}`); - } -} - -getFollowers(); diff --git a/javascript/users/following_lookup.js b/javascript/users/following_lookup.js deleted file mode 100644 index f5c76db..0000000 --- a/javascript/users/following_lookup.js +++ /dev/null @@ -1,67 +0,0 @@ -// Fetch the users being followed by a specific account, by ID -// https://developer.twitter.com/en/docs/twitter-api/users/follows/quick-start - -const needle = require('needle'); - -// this is the ID for @TwitterDev -const userId = 2244994945; -const url = `https://api.x.com/2/users/${userId}/following`; -const bearerToken = process.env.BEARER_TOKEN; - -const getFollowing = async () => { - let users = []; - let params = { - "max_results": 1000, - "user.fields": "created_at" - } - - const options = { - headers: { - "User-Agent": "v2FollowingJS", - "Authorization": `Bearer ${bearerToken}` - } - } - - let hasNextPage = true; - let nextToken = null; - console.log("Retrieving users this user is following..."); - while (hasNextPage) { - let resp = await getPage(params, options, nextToken); - if (resp && resp.meta && resp.meta.result_count && resp.meta.result_count > 0) { - if (resp.data) { - users.push.apply(users, resp.data); - } - if (resp.meta.next_token) { - nextToken = resp.meta.next_token; - } else { - hasNextPage = false; - } - } else { - hasNextPage = false; - } - } - - console.log(users); - console.log(`Got ${users.length} users.`); - -} - -const getPage = async (params, options, nextToken) => { - if (nextToken) { - params.pagination_token = nextToken; - } - - try { - const resp = await needle('get', url, params, options); - - if (resp.statusCode != 200) { - console.log(`${resp.statusCode} ${resp.statusMessage}:\n${resp.body}`); - return; - } - return resp.body; - } catch (err) { - throw new Error(`Request failed: ${err}`); - } -} - -getFollowing(); diff --git a/javascript/users/get_users_by_usernames.js b/javascript/users/get_users_by_usernames.js new file mode 100644 index 0000000..75e486a --- /dev/null +++ b/javascript/users/get_users_by_usernames.js @@ -0,0 +1,31 @@ +/** + * User Lookup - X API v2 + * + * Endpoint: GET https://api.x.com/2/users/by + * Docs: https://developer.x.com/en/docs/twitter-api/users/lookup/api-reference/get-users-by + * + * Authentication: Bearer Token (App-only) or OAuth (User Context) + * Required env vars: BEARER_TOKEN + */ + +const { Client } = require('@xdevplatform/xdk'); + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +const usernames = ['XDevelopers', 'X']; +(async () => { + try { + // Usernames to look up (up to 100) + const response = await client.users.getByUsernames(usernames, { + userFields: ['created_at', 'description', 'public_metrics'], + expansions: ['pinned_tweet_id'] + }); + + console.dir(response, { depth: null }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/get_users_by_usernames_user_context.js b/javascript/users/get_users_by_usernames_user_context.js new file mode 100644 index 0000000..7e64b9f --- /dev/null +++ b/javascript/users/get_users_by_usernames_user_context.js @@ -0,0 +1,108 @@ +// Get User objects by username, using user authentication +// https://developer.twitter.com/en/docs/twitter-api/users/lookup/quick-start + +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// These are the parameters for the API request +// specify usernames to fetch, and any additional fields that are required +// by default, only the User ID, name and username are returned +const usernames = ['XDevelopers', 'X']; // Edit usernames to look up + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.getByUsernames(usernames, { + userFields: ['created_at', 'description'], + expansions: ['pinned_tweet_id'] + }); + + console.dir(response, { + depth: null + }); + + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/get_users_me.js b/javascript/users/get_users_me.js new file mode 100644 index 0000000..591e4ef --- /dev/null +++ b/javascript/users/get_users_me.js @@ -0,0 +1,100 @@ +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK - get authenticated user + const response = await client.users.getMe({ + userFields: ['created_at', 'description'], + expansions: ['pinned_tweet_id'] + }); + + console.dir(response, { + depth: null + }); + + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/get_users_me_with_user_context.js b/javascript/users/get_users_me_with_user_context.js deleted file mode 100644 index 5166717..0000000 --- a/javascript/users/get_users_me_with_user_context.js +++ /dev/null @@ -1,146 +0,0 @@ -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}) - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// These are the parameters for the API request -// specify Tweet IDs to fetch, and any additional fields that are required -// by default, only the Tweet ID and text are returned -const params = 'user.fields=created_at,description&expansions=pinned_tweet_id' // Edit optional query parameters here - -const endpointURL = `https://api.x.com/2/users/me?{params}`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; - -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'GET' - }, token)); - - const req = await got(endpointURL, { - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2UserLookupJS" - } - }); - - if (req.body) { - return JSON.parse(req.body); - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - try { - - // Get request token - const oAuthRequestToken = await requestToken(); - - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/users/get_users_with_bearer_token.js b/javascript/users/get_users_with_bearer_token.js deleted file mode 100644 index 56c4414..0000000 --- a/javascript/users/get_users_with_bearer_token.js +++ /dev/null @@ -1,53 +0,0 @@ -// Get User objects by username, using bearer token authentication -// https://developer.twitter.com/en/docs/twitter-api/users/lookup/quick-start - -const needle = require('needle'); - -// The code below sets the bearer token from your environment variables -// To set environment variables on macOS or Linux, run the export command below from the terminal: -// export BEARER_TOKEN='YOUR-TOKEN' -const token = process.env.BEARER_TOKEN; - -const endpointURL = "https://api.x.com/2/users/by?usernames=" - -async function getRequest() { - - // These are the parameters for the API request - // specify User names to fetch, and any additional fields that are required - // by default, only the User ID, name and user name are returned - const params = { - usernames: "TwitterDev,TwitterAPI", // Edit usernames to look up - "user.fields": "created_at,description", // Edit optional query parameters here - "expansions": "pinned_tweet_id" - } - - // this is the HTTP header that adds bearer token authentication - const res = await needle('get', endpointURL, params, { - headers: { - "User-Agent": "v2UserLookupJS", - "authorization": `Bearer ${token}` - } - }) - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request') - } -} - -(async () => { - - try { - // Make request - const response = await getRequest(); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/users/get_users_with_user_context.js b/javascript/users/get_users_with_user_context.js deleted file mode 100644 index 4cceedb..0000000 --- a/javascript/users/get_users_with_user_context.js +++ /dev/null @@ -1,150 +0,0 @@ -// Get User objects by username, using user authentication -// https://developer.twitter.com/en/docs/twitter-api/users/lookup/quick-start - -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}) - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// These are the parameters for the API request -// specify Tweet IDs to fetch, and any additional fields that are required -// by default, only the Tweet ID and text are returned -const usernames = 'TwitterDev,TwitterAPI' // Edit usernames to look up -const params = 'user.fields=created_at,description&expansions=pinned_tweet_id' // Edit optional query parameters here - -const endpointURL = `https://api.x.com/2/users/by?usernames=${usernames}&${params}`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; - -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'GET' - }, token)); - - const req = await got(endpointURL, { - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2UserLookupJS" - } - }); - - if (req.body) { - return JSON.parse(req.body); - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - try { - - // Get request token - const oAuthRequestToken = await requestToken(); - - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/users/like/get_liked_posts.js b/javascript/users/like/get_liked_posts.js new file mode 100644 index 0000000..efdca5e --- /dev/null +++ b/javascript/users/like/get_liked_posts.js @@ -0,0 +1,130 @@ +// Get Liked Posts by User ID using OAuth 2.0 to authorize the user +// https://developer.twitter.com/en/docs/twitter-api/tweets/likes/api-reference/get-users-id-liked_tweets + +const { + Client, + OAuth2, + PostPaginator, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// You can replace the ID given with the User ID you wish to get liked posts for. +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'like.read', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + console.log("Retrieving liked posts..."); + + // Use paginator for automatic pagination + const likedPosts = new PostPaginator( + async (token) => { + const res = await client.users.getLikedPosts(userId, { + maxResults: 100, + paginationToken: token, + tweetFields: ['lang', 'author_id'], + userFields: ['created_at'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; + } + ); + + // Fetch all pages + await likedPosts.fetchNext(); + while (!likedPosts.done) { + await likedPosts.fetchNext(); + } + + console.dir(likedPosts.posts, { + depth: null + }); + + console.log(`Got ${likedPosts.posts.length} liked posts for user ID ${userId}!`); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); + diff --git a/javascript/users/like/like_post.js b/javascript/users/like/like_post.js new file mode 100644 index 0000000..594cf32 --- /dev/null +++ b/javascript/users/like/like_post.js @@ -0,0 +1,104 @@ +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticating user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +// You can replace Post ID given with the Post ID you wish to like. +// You can find a Post ID by using the Post lookup endpoint +const postId = "1354143047324299264"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write', 'offline.access', 'like.write'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.likePost(userId, {body: {tweet_id: postId}}); + console.dir(response, { + depth: null + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); + diff --git a/javascript/users/like/unlike_post.js b/javascript/users/like/unlike_post.js new file mode 100644 index 0000000..261afe7 --- /dev/null +++ b/javascript/users/like/unlike_post.js @@ -0,0 +1,104 @@ +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticating user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +// You can replace Post ID given with the Post ID you wish to unlike. +// You can find a Post ID by using the Post lookup endpoint +const postId = "1354143047324299264"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write', 'offline.access', 'like.write'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.unlikePost(userId, postId); + console.dir(response, { + depth: null + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); + diff --git a/javascript/users/lists/follow_list.js b/javascript/users/lists/follow_list.js new file mode 100644 index 0000000..dba9e36 --- /dev/null +++ b/javascript/users/lists/follow_list.js @@ -0,0 +1,104 @@ +// Follow a list using OAuth 2.0 to authorize the user +// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +// Be sure to add replace list-id-to-follow with the list id you wish to follow. +const listId = "list-id-to-follow"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'list.read', 'list.write', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.followList(userId, {body: {list_id: listId}}); + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/lists/get_followed_lists.js b/javascript/users/lists/get_followed_lists.js new file mode 100644 index 0000000..57efeb3 --- /dev/null +++ b/javascript/users/lists/get_followed_lists.js @@ -0,0 +1,29 @@ +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); +const id = "user-id"; + +(async () => { + try { + // These are the parameters for the API request + // by default, only the List ID and name are returned + const response = await client.users.getFollowedLists(id, { + listFields: ['owner_id'], // Edit optional query parameters here + expansions: ['owner_id'], // expansions is used to include the user object + userFields: ['created_at', 'verified'] // Edit optional query parameters here + }); + + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/lists/get_list_memberships.js b/javascript/users/lists/get_list_memberships.js new file mode 100644 index 0000000..6ea2f7d --- /dev/null +++ b/javascript/users/lists/get_list_memberships.js @@ -0,0 +1,29 @@ +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); +const id = "user-id"; + +(async () => { + try { + // These are the parameters for the API request + // by default, only the List ID and name are returned + const response = await client.users.getListMemberships(id, { + listFields: ['owner_id'], // Edit optional query parameters here + expansions: ['owner_id'], // expansions is used to include the user object + userFields: ['created_at', 'verified'] // Edit optional query parameters here + }); + + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/lists/get_owned_lists.js b/javascript/users/lists/get_owned_lists.js new file mode 100644 index 0000000..465e238 --- /dev/null +++ b/javascript/users/lists/get_owned_lists.js @@ -0,0 +1,29 @@ +const { Client } = require('@xdevplatform/xdk'); + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); +const id = "user-id"; + +(async () => { + try { + // These are the parameters for the API request + // by default, only the List ID and name are returned + const response = await client.users.getOwnedLists(id, { + listFields: ['owner_id'], // Edit optional query parameters here + expansions: ['owner_id'], // expansions is used to include the user object + userFields: ['created_at', 'verified'] // Edit optional query parameters here + }); + + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/lists/pin_list.js b/javascript/users/lists/pin_list.js new file mode 100644 index 0000000..fb70c45 --- /dev/null +++ b/javascript/users/lists/pin_list.js @@ -0,0 +1,104 @@ +// Pin a list using OAuth 2.0 to authorize the user +// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +// Be sure to add replace list-id-to-pin with the list id you wish to pin. +const listId = "list-id-to-pin"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'list.read', 'list.write', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.pinList(userId, {list_id: listId}); + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/lists/unfollow_list.js b/javascript/users/lists/unfollow_list.js new file mode 100644 index 0000000..0fe0760 --- /dev/null +++ b/javascript/users/lists/unfollow_list.js @@ -0,0 +1,104 @@ +// Unfollow a list using OAuth 2.0 to authorize the user +// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +// Be sure to replace list-id-to-unfollow with the list id you wish to unfollow. +const listId = "list-id-to-unfollow"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'list.read', 'list.write', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.unfollowList(userId, listId); + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/lists/unpin_list.js b/javascript/users/lists/unpin_list.js new file mode 100644 index 0000000..d37b4fe --- /dev/null +++ b/javascript/users/lists/unpin_list.js @@ -0,0 +1,104 @@ +// Unpin a list using OAuth 2.0 to authorize the user +// https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +// Be sure to replace list-id-to-unpin with the list id you wish to unpin. +const listId = "list-id-to-unpin"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'list.read', 'list.write', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.unpinList(userId, listId); + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/lookup.js b/javascript/users/lookup.js deleted file mode 100644 index 3cfbed9..0000000 --- a/javascript/users/lookup.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * User Lookup - X API v2 - * - * Endpoint: GET https://api.x.com/2/users/by - * Docs: https://developer.x.com/en/docs/twitter-api/users/lookup/api-reference/get-users-by - * - * Authentication: Bearer Token (App-only) or OAuth (User Context) - * Required env vars: BEARER_TOKEN - */ - -const needle = require('needle'); - -const token = process.env.BEARER_TOKEN; -const endpointURL = "https://api.x.com/2/users/by"; - -async function getRequest() { - // Usernames to look up (up to 100 comma-separated) - const params = { - "usernames": "XDevelopers,X", - "user.fields": "created_at,description,public_metrics" - }; - - const res = await needle('get', endpointURL, params, { - headers: { - "User-Agent": "v2UserLookupJS", - "authorization": `Bearer ${token}` - } - }); - - if (res.body) { - return res.body; - } else { - throw new Error('Unsuccessful request'); - } -} - -(async () => { - try { - const response = await getRequest(); - console.dir(response, { depth: null }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/users/lookup_blocks.js b/javascript/users/lookup_blocks.js deleted file mode 100644 index a9ff459..0000000 --- a/javascript/users/lookup_blocks.js +++ /dev/null @@ -1,140 +0,0 @@ -// Block a user, using user authentication -// https://developer.twitter.com/en/docs/twitter-api/users/blocks/quick-start -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}) - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; -const endpointURL = `https://api.x.com/2/users/${id}/blocking`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'GET' - }, token)); - - const req = await got.get(endpointURL, { - responseType: 'json', - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2BlocksLookupJS" - } - }); - if (req.body) { - return req.body; - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/users/lookup_mutes.js b/javascript/users/lookup_mutes.js deleted file mode 100644 index d8c9d39..0000000 --- a/javascript/users/lookup_mutes.js +++ /dev/null @@ -1,142 +0,0 @@ -// Retrieve accounts muted by authenticated user -// https://developer.twitter.com/en/docs/twitter-api/users/mutes/quick-start -const got = require("got"); -const crypto = require("crypto"); -const OAuth = require("oauth-1.0a"); -const qs = require("querystring"); - -const readline = require("readline").createInterface({ - input: process.stdin, - output: process.stdout, -}); - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; -const endpointURL = `https://api.x.com/2/users/${id}/muting`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = - "https://api.x.com/oauth/request_token?oauth_callback=oob"; -const authorizeURL = new URL("https://api.x.com/oauth/authorize"); -const accessTokenURL = "https://api.x.com/oauth/access_token"; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret, - }, - signature_method: "HMAC-SHA1", - hash_function: (baseString, key) => - crypto.createHmac("sha1", key).update(baseString).digest("base64"), -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: requestTokenURL, - method: "POST", - }) - ); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function accessToken({ oauth_token, oauth_token_secret }, verifier) { - const authHeader = oauth.toHeader( - oauth.authorize({ - url: accessTokenURL, - method: "POST", - }) - ); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}`; - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"], - }, - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error("Cannot get an OAuth request token"); - } -} - -async function getRequest({ oauth_token, oauth_token_secret }) { - const token = { - key: oauth_token, - secret: oauth_token_secret, - }; - - const authHeader = oauth.toHeader( - oauth.authorize( - { - url: endpointURL, - method: "GET", - }, - token - ) - ); - - const req = await got.get(endpointURL, { - responseType: "json", - headers: { - Authorization: authHeader["Authorization"], - "user-agent": "v2MutesLookupJS", - }, - }); - if (req.body) { - return req.body; - } else { - throw new Error("Unsuccessful request"); - } -} - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append( - "oauth_token", - oAuthRequestToken.oauth_token - ); - console.log("Please go here and authorize:", authorizeURL.href); - const pin = await input("Paste the PIN here: "); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null, - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/users/mute/get_muting.js b/javascript/users/mute/get_muting.js new file mode 100644 index 0000000..9115a9b --- /dev/null +++ b/javascript/users/mute/get_muting.js @@ -0,0 +1,101 @@ +// Retrieve accounts muted by authenticated user +// https://developer.twitter.com/en/docs/twitter-api/users/mutes/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write', 'offline.access', 'mute.read'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.getMuting(userId); + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/mute/mute_user.js b/javascript/users/mute/mute_user.js new file mode 100644 index 0000000..a0f0992 --- /dev/null +++ b/javascript/users/mute/mute_user.js @@ -0,0 +1,105 @@ +// mute a user, using user authentication +// https://developer.twitter.com/en/docs/twitter-api/users/mutes/quick-start +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +// Be sure to add replace id-to-mute with the user id you wish to mute. +// You can find a user ID by using the user lookup endpoint +const targetUserId = "id-to-mute"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write', 'offline.access', 'mute.write'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.muteUser(userId, { body: { target_user_id: targetUserId } }); + console.dir(response, { + depth: null + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/mute/unmute_user.js b/javascript/users/mute/unmute_user.js new file mode 100644 index 0000000..23666e7 --- /dev/null +++ b/javascript/users/mute/unmute_user.js @@ -0,0 +1,104 @@ +// Unmute a user, using user authentication +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const sourceUserId = "your-user-id"; + +// Be sure to add replace the id-to-unmute with the user id of the you wish to unmute. +// You can find a user ID by using the user lookup endpoint +const targetUserId = "id-to-unmute"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write', 'offline.access', 'mute.write'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.unmuteUser(sourceUserId, targetUserId); + console.dir(response, { + depth: null + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/mute_a_user.js b/javascript/users/mute_a_user.js deleted file mode 100644 index 73d12f2..0000000 --- a/javascript/users/mute_a_user.js +++ /dev/null @@ -1,150 +0,0 @@ -// mute a user, using user authentication -// https://developer.twitter.com/en/docs/twitter-api/users/mutes/quick-start -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}) - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const id = "your-user-id"; - -// Be sure to add replace id-to-mute with the user id you wish to mute. -// You can find a user ID by using the user lookup endpoint -const data = { - "target_user_id": "id-to-mute" -} - -const endpointURL = `https://api.x.com/2/users/${id}/muting`; - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - headers: { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'POST' - }, token)); - - const req = await got.post(endpointURL, { - json: data, - responseType: 'json', - headers: { - Authorization: authHeader["Authorization"], - 'user-agent': "v2muteUserJS", - 'content-type': "application/json", - 'accept': "application/json" - } - }); - if (req.body) { - return req.body; - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})(); diff --git a/javascript/users/repost/repost_post.js b/javascript/users/repost/repost_post.js new file mode 100644 index 0000000..d740f62 --- /dev/null +++ b/javascript/users/repost/repost_post.js @@ -0,0 +1,104 @@ +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +// You can replace the given Post ID with the Post ID you want to repost +// You can find a Post ID by using the Post lookup endpoint +const postId = "1412865600439738368"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.repostPost(userId, { body: { tweet_id: postId } }); + console.dir(response, { + depth: null + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); + diff --git a/javascript/users/repost/unrepost_post.js b/javascript/users/repost/unrepost_post.js new file mode 100644 index 0000000..ff1fdb5 --- /dev/null +++ b/javascript/users/repost/unrepost_post.js @@ -0,0 +1,104 @@ +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require('readline').createInterface({ + input: process.stdin, + output: process.stdout +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticating user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +// You can replace the given Post ID with the Post ID you want to undo repost +// You can find a Post ID by using the Post lookup endpoint +const sourceTweetId = "1412865600439738368"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'tweet.write', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log('Please go here and authorize:', authUrl); + + // Input callback URL from terminal + const redirectCallback = await input('Paste the redirected callback URL here: '); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.unrepostPost(userId, sourceTweetId); + console.dir(response, { + depth: null + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); + diff --git a/javascript/users/timeline/get_home_timeline.js b/javascript/users/timeline/get_home_timeline.js new file mode 100644 index 0000000..e5f9643 --- /dev/null +++ b/javascript/users/timeline/get_home_timeline.js @@ -0,0 +1,101 @@ +// Get reverse chronological home timeline +// https://developer.twitter.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-reverse-chronological-timeline +const { + Client, + OAuth2, + generateCodeVerifier, + generateCodeChallenge +} = require('@xdevplatform/xdk'); + +const readline = require("readline").createInterface({ + input: process.stdin, + output: process.stdout, +}); + +// The code below sets the client ID and client secret from your environment variables +// To set environment variables on macOS or Linux, run the export commands below from the terminal: +// export CLIENT_ID='YOUR-CLIENT-ID' +// export CLIENT_SECRET='YOUR-CLIENT-SECRET' +const clientId = process.env.CLIENT_ID; +const clientSecret = process.env.CLIENT_SECRET; + +// Be sure to replace your-user-id with your own user ID or one of an authenticated user +// You can find a user ID by using the user lookup endpoint +const userId = "your-user-id"; + +async function input(prompt) { + return new Promise((resolve) => { + readline.question(prompt, (out) => { + readline.close(); + resolve(out); + }); + }); +} + +// Helper function to parse callback URL +const getQueryStringParams = (query) => { + return query + ? (/^[?#]/.test(query) ? query.slice(1) : query) + .split(/[\?\&]/) + .reduce((params, param) => { + let [key, value] = param.split("="); + params[key] = value + ? decodeURIComponent(value.replace(/\+/g, " ")) + : ""; + return params; + }, {}) + : {}; +}; + +(async () => { + try { + // Configure OAuth 2.0 + const oauth2Config = { + clientId: clientId, + clientSecret: clientSecret, + redirectUri: 'https://example.com', + scope: ['tweet.read', 'users.read', 'offline.access'] + }; + + const oauth2 = new OAuth2(oauth2Config); + + // Generate PKCE parameters + const state = 'example-state'; + const codeVerifier = generateCodeVerifier(); + const codeChallenge = await generateCodeChallenge(codeVerifier); + + oauth2.setPkceParameters(codeVerifier, codeChallenge); + + // Get authorization URL + const authUrl = await oauth2.getAuthorizationUrl(state); + console.log("Please go here and authorize:", authUrl); + + // Input callback URL from terminal + const redirectCallback = await input("Paste the redirected callback URL here: "); + + // Parse callback + const { state: returnedState, code } = getQueryStringParams(redirectCallback); + if (returnedState !== state) { + console.log("State doesn't match"); + process.exit(-1); + } + + // Exchange code for tokens + const tokens = await oauth2.exchangeCode(code, codeVerifier); + + // Create client with access token + const client = new Client({ + accessToken: tokens.access_token + }); + + // Make the request using SDK + const response = await client.users.getTimeline(userId); + console.dir(response, { + depth: null, + }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/timeline/get_mentions.js b/javascript/users/timeline/get_mentions.js new file mode 100644 index 0000000..502b777 --- /dev/null +++ b/javascript/users/timeline/get_mentions.js @@ -0,0 +1,51 @@ +// Get User mentions timeline by user ID +// https://developer.twitter.com/en/docs/twitter-api/tweets/timelines/quick-start + +const { Client, PostPaginator } = require('@xdevplatform/xdk'); + +const userId = '2244994945'; + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const bearerToken = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: bearerToken }); + +// this is the ID for @TwitterDev +const getUserMentions = async () => { + console.log("Retrieving mentions..."); + + // Use paginator for automatic pagination + const userMentions = new PostPaginator( + async (token) => { + const res = await client.users.getMentions(userId, { + maxResults: 100, + paginationToken: token, + tweetFields: ['created_at'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; + } + ); + + // Fetch all pages + await userMentions.fetchNext(); + while (!userMentions.done) { + await userMentions.fetchNext(); + } + + console.dir(userMentions.posts, { + depth: null + }); + + console.log(`Got ${userMentions.posts.length} mentions for user ID ${userId}!`); +} + +getUserMentions().catch(err => { + console.error('Error:', err); + process.exit(-1); +}); diff --git a/javascript/users/timeline/get_posts.js b/javascript/users/timeline/get_posts.js new file mode 100644 index 0000000..a646d84 --- /dev/null +++ b/javascript/users/timeline/get_posts.js @@ -0,0 +1,35 @@ +/** + * User Posts Timeline - X API v2 + * + * Endpoint: GET https://api.x.com/2/users/:id/posts + * Docs: https://developer.x.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-tweets + * + * Authentication: Bearer Token (App-only) or OAuth (User Context) + * Required env vars: BEARER_TOKEN + * + * This is a simple example that makes a single request. + * For automatic pagination, see user_posts_paginated.js + */ + +const { Client } = require('@xdevplatform/xdk'); + +const token = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: token }); + +// Replace with the user ID you want to get posts for +const userId = "2244994945"; + +(async () => { + try { + const response = await client.users.getPosts(userId, { + tweetFields: ['created_at', 'public_metrics'], + maxResults: 10 + }); + + console.dir(response, { depth: null }); + } catch (e) { + console.log(e); + process.exit(-1); + } + process.exit(); +})(); diff --git a/javascript/users/timeline/get_posts_paginated.js b/javascript/users/timeline/get_posts_paginated.js new file mode 100644 index 0000000..17640ee --- /dev/null +++ b/javascript/users/timeline/get_posts_paginated.js @@ -0,0 +1,69 @@ +/** + * User Posts Timeline (Paginated) - X API v2 + * + * Endpoint: GET https://api.x.com/2/users/:id/posts + * Docs: https://developer.x.com/en/docs/twitter-api/tweets/timelines/api-reference/get-users-id-tweets + * + * Authentication: Bearer Token (App-only) or OAuth (User Context) + * Required env vars: BEARER_TOKEN + * + * This example demonstrates automatic pagination using PostPaginator + * to fetch all pages of results. For a simple single-request example, + * see user_posts.js + */ + +const { Client, PostPaginator } = require('@xdevplatform/xdk'); + +// this is the ID for @TwitterDev +const userId = "2244994945"; + +// The code below sets the bearer token from your environment variables +// To set environment variables on macOS or Linux, run the export command below from the terminal: +// export BEARER_TOKEN='YOUR-TOKEN' +const bearerToken = process.env.BEARER_TOKEN; +const client = new Client({ bearerToken: bearerToken }); + +const getUserTweets = async () => { + console.log("Retrieving Tweets..."); + + // Use paginator for automatic pagination + // we request the author_id expansion so that we can print out the user name later + const userTweets = new PostPaginator( + async (token) => { + const res = await client.users.getPosts(userId, { + maxResults: 100, + paginationToken: token, + tweetFields: ['created_at'], + expansions: ['author_id'] + }); + return { + data: res.data ?? [], + meta: res.meta, + includes: res.includes, + errors: res.errors + }; + } + ); + + // Fetch all pages + await userTweets.fetchNext(); + while (!userTweets.done) { + await userTweets.fetchNext(); + } + + let userName; + if (userTweets.includes?.users && userTweets.includes.users.length > 0) { + userName = userTweets.includes.users[0].username; + } + + console.dir(userTweets.posts, { + depth: null + }); + console.log(`Got ${userTweets.posts.length} Tweets from ${userName || 'user'} (user ID ${userId})!`); +} + +getUserTweets().catch(err => { + console.error('Error:', err); + process.exit(-1); +}); + diff --git a/javascript/users/unmute_a_user.js b/javascript/users/unmute_a_user.js deleted file mode 100644 index ddd421c..0000000 --- a/javascript/users/unmute_a_user.js +++ /dev/null @@ -1,145 +0,0 @@ -// Unmute a user, using user authentication -const got = require('got'); -const crypto = require('crypto'); -const OAuth = require('oauth-1.0a'); -const qs = require('querystring'); - -const readline = require('readline').createInterface({ - input: process.stdin, - output: process.stdout -}) - - -// The code below sets the consumer key and consumer secret from your environment variables -// To set environment variables on macOS or Linux, run the export commands below from the terminal: -// export CONSUMER_KEY='YOUR-KEY' -// export CONSUMER_SECRET='YOUR-SECRET' -const consumer_key = process.env.CONSUMER_KEY; -const consumer_secret = process.env.CONSUMER_SECRET; - - -// Be sure to replace your-user-id with your own user ID or one of an authenticated user -// You can find a user ID by using the user lookup endpoint -const source_user_id = "your-user-id"; - - -// Be sure to add replace the id-to-unmute with the user id of the you wish to unmute. -// You can find a user ID by using the user lookup endpoint -const target_user_id = "id-to-unmute" - -const endpointURL = `https://api.x.com/2/users/${source_user_id}/muting/${target_user_id}`; - - -// this example uses PIN-based OAuth to authorize the user -const requestTokenURL = 'https://api.x.com/oauth/request_token?oauth_callback=oob'; -const authorizeURL = new URL('https://api.x.com/oauth/authorize'); -const accessTokenURL = 'https://api.x.com/oauth/access_token'; -const oauth = OAuth({ - consumer: { - key: consumer_key, - secret: consumer_secret - }, - signature_method: 'HMAC-SHA1', - hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64') -}); - -async function input(prompt) { - return new Promise(async (resolve, reject) => { - readline.question(prompt, (out) => { - readline.close(); - resolve(out); - }); - }); -} - -async function requestToken() { - const authHeader = oauth.toHeader(oauth.authorize({ - url: requestTokenURL, - method: 'POST' - })); - - const req = await got.post(requestTokenURL, { - : { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function accessToken({ - oauth_token, - oauth_token_secret -}, verifier) { - const authHeader = oauth.toHeader(oauth.authorize({ - url: accessTokenURL, - method: 'POST' - })); - const path = `https://api.x.com/oauth/access_token?oauth_verifier=${verifier}&oauth_token=${oauth_token}` - const req = await got.post(path, { - : { - Authorization: authHeader["Authorization"] - } - }); - if (req.body) { - return qs.parse(req.body); - } else { - throw new Error('Cannot get an OAuth request token'); - } -} - - -async function getRequest({ - oauth_token, - oauth_token_secret -}) { - - const token = { - key: oauth_token, - secret: oauth_token_secret - }; - - const authHeader = oauth.toHeader(oauth.authorize({ - url: endpointURL, - method: 'DELETE' - }, token)); - - const req = await got.post(endpointURL, { - : { - Authorization: authHeader["Authorization"], - 'user-agent': "v2UnmuteUserJS" - } - }); - if (req.body) { - return JSON.parse(req.body); - } else { - throw new Error('Unsuccessful request'); - } -} - - -(async () => { - try { - // Get request token - const oAuthRequestToken = await requestToken(); - // Get authorization - authorizeURL.searchParams.append('oauth_token', oAuthRequestToken.oauth_token); - console.log('Please go here and authorize:', authorizeURL.href); - const pin = await input('Paste the PIN here: '); - // Get the access token - const oAuthAccessToken = await accessToken(oAuthRequestToken, pin.trim()); - // Make the request - const response = await getRequest(oAuthAccessToken); - console.dir(response, { - depth: null - }); - } catch (e) { - console.log(e); - process.exit(-1); - } - process.exit(); -})();