Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,16 @@ export async function requestApi<T>(
auth instanceof TwitterGuestAuth &&
auth.options?.experimental?.xClientTransactionId
) {
const transactionId = await generateTransactionId(
url,
auth.fetch.bind(auth),
method,
);
headers.set('x-client-transaction-id', transactionId);
try {
const transactionId = await generateTransactionId(
url,
auth.fetch.bind(auth),
method,
);
headers.set('x-client-transaction-id', transactionId);
} catch (err) {
log('Failed to generate x-client-transaction-id, falling back gracefully: %s', (err as Error).message);
}
}

if (body && method === 'POST') {
Expand Down
16 changes: 10 additions & 6 deletions src/auth-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -969,12 +969,16 @@ export class TwitterUserAuth extends TwitterGuestAuth {

// Generate x-client-transaction-id if enabled - real browsers send this during login.
if (this.options?.experimental?.xClientTransactionId) {
const transactionId = await generateTransactionId(
onboardingTaskUrl,
this.fetch.bind(this),
'POST',
);
headers.set('x-client-transaction-id', transactionId);
try {
const transactionId = await generateTransactionId(
onboardingTaskUrl,
this.fetch.bind(this),
'POST',
);
headers.set('x-client-transaction-id', transactionId);
} catch (err) {
log('Failed to generate x-client-transaction-id, falling back gracefully: %s', (err as Error).message);
}
}

// Strip flow_name from the body: real browsers only send it in the URL query parameter.
Expand Down
11 changes: 7 additions & 4 deletions src/tweets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,10 +377,13 @@ export async function getLatestTweet(
): Promise<Tweet | null | void> {
const timeline = getTweets(user, max, auth);

// No point looping if max is 1, just use first entry.
return max === 1
? (await timeline.next()).value
: await getTweetWhere(timeline, { isRetweet: includeRetweets });
return getTweetWhere(timeline, (tweet) => {
// Skip pinned tweets; they always appear first in the timeline.
if (tweet.isPin) return false;
// If includeRetweets is false, skip retweets too.
if (!includeRetweets && tweet.isRetweet) return false;
return true;
});
}

export interface TweetResultByRestId {
Expand Down