1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { searchParams } from "https://esm.town/v/stevekrouse/searchParams";
import { twitterJSON } from "https://esm.town/v/stevekrouse/twitterJSON";
import { twitterUser } from "https://esm.town/v/stevekrouse/twitterUser";
export async function twitterSearch({
query,
start_time,
bearerToken,
...rest
}: {
query?: string;
start_time?: Date;
bearerToken: string;
}): Promise<TweetResult[]> {
const res = await twitterJSON({
url: `https://api.twitter.com/2/tweets/search/recent?query=${await searchParams(
{
query,
start_time: start_time?.toISOString(),
expansions: ["author_id"], // ["referenced_tweets.id", "attachments.media_keys"]]
["tweet.fields"]: ["public_metrics", "referenced_tweets"], // ["attachments"]
...rest,
},
)}`,
bearerToken: bearerToken,
});
if (res.errors) {
console.error("twitterSearch error", JSON.stringify(res));
throw new Error(JSON.stringify(res.errors));
}
return Promise.all(
(res.data || []).map(async (tweet) => {
const { data: author } = await twitterUser({
id: tweet.author_id,
bearerToken,
});
return {
...tweet,
author_name: author?.name,
author_username: author?.username,
public_metrics: tweet.public_metrics,
referenced_tweets: tweet.referenced_tweets,
is_retweet: tweet.referenced_tweets?.some(ref => ref.type === "retweeted") ?? false,
is_reply: tweet.referenced_tweets?.some(ref => ref.type === "replied_to") ?? false,
is_quote: tweet.referenced_tweets?.some(ref => ref.type === "quoted") ?? false,
};
}),
);
}
interface TweetResult {
author_id: string;
text: string;
id: string;
edit_history_tweet_ids: string[];
author_name?: string;
author_username?: string;
public_metrics?: {
retweet_count: number;
reply_count: number;
like_count: number;
quote_count: number;
};
referenced_tweets?: {
type: "retweeted" | "quoted" | "replied_to";
id: string;
}[];
is_retweet?: boolean;
is_reply?: boolean;
is_quote?: boolean;
}