scrapebadger 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -5
- package/dist/{index-DQ_jDTcQ.d.cts → index-CIZUd1Zr.d.cts} +341 -1
- package/dist/{index-DQ_jDTcQ.d.ts → index-CIZUd1Zr.d.ts} +341 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +317 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +317 -20
- package/dist/index.mjs.map +1 -1
- package/dist/twitter/index.d.cts +1 -1
- package/dist/twitter/index.d.ts +1 -1
- package/dist/twitter/index.js +255 -10
- package/dist/twitter/index.js.map +1 -1
- package/dist/twitter/index.mjs +255 -11
- package/dist/twitter/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -124,6 +124,19 @@ var BaseClient = class {
|
|
|
124
124
|
* Make an HTTP request to the API.
|
|
125
125
|
*/
|
|
126
126
|
async request(path, options = {}) {
|
|
127
|
+
const { data } = await this.requestRaw(path, options);
|
|
128
|
+
return data;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Make an HTTP request and return both data and rate limit headers.
|
|
132
|
+
*/
|
|
133
|
+
async requestWithHeaders(path, options = {}) {
|
|
134
|
+
return this.requestRaw(path, options);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Internal method that builds the request and executes it, returning data and rate limit info.
|
|
138
|
+
*/
|
|
139
|
+
async requestRaw(path, options = {}) {
|
|
127
140
|
const { method = "GET", params, body, headers = {} } = options;
|
|
128
141
|
const url = new URL(path, this.config.baseUrl);
|
|
129
142
|
if (params) {
|
|
@@ -137,7 +150,7 @@ var BaseClient = class {
|
|
|
137
150
|
"Content-Type": "application/json",
|
|
138
151
|
Accept: "application/json",
|
|
139
152
|
"X-API-Key": this.config.apiKey,
|
|
140
|
-
"User-Agent": "scrapebadger-node/0.1
|
|
153
|
+
"User-Agent": "scrapebadger-node/0.3.1",
|
|
141
154
|
...headers
|
|
142
155
|
};
|
|
143
156
|
const fetchOptions = {
|
|
@@ -156,8 +169,10 @@ var BaseClient = class {
|
|
|
156
169
|
let lastError;
|
|
157
170
|
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
158
171
|
try {
|
|
159
|
-
const
|
|
160
|
-
|
|
172
|
+
const httpResponse = await this.fetchWithTimeout(url, options);
|
|
173
|
+
const data = await this.handleResponse(httpResponse);
|
|
174
|
+
const rateLimit = this.parseRateLimitHeaders(httpResponse.headers);
|
|
175
|
+
return { data, rateLimit };
|
|
161
176
|
} catch (error) {
|
|
162
177
|
lastError = error;
|
|
163
178
|
if (error instanceof ScrapeBadgerError && !(error instanceof RateLimitError)) {
|
|
@@ -167,18 +182,56 @@ var BaseClient = class {
|
|
|
167
182
|
break;
|
|
168
183
|
}
|
|
169
184
|
const delay = this.config.retryDelay * Math.pow(2, attempt);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
185
|
+
const delaySec = Math.round(delay / 1e3);
|
|
186
|
+
const attemptNum = attempt + 1;
|
|
187
|
+
const maxRetries = this.config.maxRetries;
|
|
188
|
+
if (error instanceof RateLimitError) {
|
|
189
|
+
console.warn(
|
|
190
|
+
`\x1B[33m\u26A0 ScrapeBadger: 429 Rate Limited \u2014 retrying in ${delaySec}s (attempt ${attemptNum}/${maxRetries})\x1B[0m`
|
|
191
|
+
);
|
|
192
|
+
if (error.retryAfter) {
|
|
193
|
+
const retryDelay = (error.retryAfter - Date.now() / 1e3) * 1e3;
|
|
194
|
+
if (retryDelay > 0 && retryDelay < 6e4) {
|
|
195
|
+
await this.sleep(retryDelay);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
175
198
|
}
|
|
199
|
+
} else if (error instanceof TimeoutError) {
|
|
200
|
+
console.warn(
|
|
201
|
+
`\x1B[33m\u26A0 ScrapeBadger: TimeoutError \u2014 retrying in ${delaySec}s (attempt ${attemptNum}/${maxRetries})\x1B[0m`
|
|
202
|
+
);
|
|
203
|
+
} else if (error instanceof ServerError) {
|
|
204
|
+
console.warn(
|
|
205
|
+
`\x1B[33m\u26A0 ScrapeBadger: ${error.statusCode} ${error.message} \u2014 retrying in ${delaySec}s (attempt ${attemptNum}/${maxRetries})\x1B[0m`
|
|
206
|
+
);
|
|
207
|
+
} else {
|
|
208
|
+
console.warn(
|
|
209
|
+
`\x1B[33m\u26A0 ScrapeBadger: ${error.name} \u2014 retrying in ${delaySec}s (attempt ${attemptNum}/${maxRetries})\x1B[0m`
|
|
210
|
+
);
|
|
176
211
|
}
|
|
177
212
|
await this.sleep(delay);
|
|
178
213
|
}
|
|
179
214
|
}
|
|
180
215
|
throw lastError ?? new ScrapeBadgerError("Request failed after retries");
|
|
181
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Parse rate limit headers from an HTTP response.
|
|
219
|
+
*/
|
|
220
|
+
parseRateLimitHeaders(headers) {
|
|
221
|
+
const limit = headers.get("X-RateLimit-Limit");
|
|
222
|
+
const remaining = headers.get("X-RateLimit-Remaining");
|
|
223
|
+
const reset = headers.get("X-RateLimit-Reset");
|
|
224
|
+
if (limit === null || remaining === null || reset === null) {
|
|
225
|
+
return void 0;
|
|
226
|
+
}
|
|
227
|
+
const parsedLimit = parseInt(limit, 10);
|
|
228
|
+
const parsedRemaining = parseInt(remaining, 10);
|
|
229
|
+
const parsedReset = parseInt(reset, 10);
|
|
230
|
+
if (isNaN(parsedLimit) || isNaN(parsedRemaining) || isNaN(parsedReset)) {
|
|
231
|
+
return void 0;
|
|
232
|
+
}
|
|
233
|
+
return { limit: parsedLimit, remaining: parsedRemaining, reset: parsedReset };
|
|
234
|
+
}
|
|
182
235
|
/**
|
|
183
236
|
* Fetch with timeout support.
|
|
184
237
|
*/
|
|
@@ -260,7 +313,7 @@ var BaseClient = class {
|
|
|
260
313
|
// src/internal/config.ts
|
|
261
314
|
var DEFAULT_BASE_URL = "https://scrapebadger.com";
|
|
262
315
|
var DEFAULT_TIMEOUT = 3e4;
|
|
263
|
-
var DEFAULT_MAX_RETRIES =
|
|
316
|
+
var DEFAULT_MAX_RETRIES = 10;
|
|
264
317
|
var DEFAULT_RETRY_DELAY = 1e3;
|
|
265
318
|
function resolveConfig(config) {
|
|
266
319
|
if (!config.apiKey) {
|
|
@@ -289,12 +342,26 @@ function createPaginatedResponse(data, cursor) {
|
|
|
289
342
|
hasMore: !!cursor
|
|
290
343
|
};
|
|
291
344
|
}
|
|
345
|
+
var RATE_LIMIT_WARN_THRESHOLD = 0.2;
|
|
292
346
|
async function* paginate(fetchPage, options = {}) {
|
|
293
347
|
const { maxItems } = options;
|
|
294
348
|
let cursor;
|
|
295
349
|
let totalYielded = 0;
|
|
296
350
|
do {
|
|
297
|
-
const response = await fetchPage(cursor);
|
|
351
|
+
const { response, rateLimit } = await fetchPage(cursor);
|
|
352
|
+
if (rateLimit) {
|
|
353
|
+
const { limit, remaining, reset } = rateLimit;
|
|
354
|
+
if (limit > 0 && remaining / limit < RATE_LIMIT_WARN_THRESHOLD) {
|
|
355
|
+
const nowSec = Date.now() / 1e3;
|
|
356
|
+
const windowRemainingSec = Math.max(reset - nowSec, 1);
|
|
357
|
+
const delayMs = remaining > 0 ? windowRemainingSec / remaining * 1e3 : windowRemainingSec * 1e3;
|
|
358
|
+
const resetInSec = Math.round(windowRemainingSec);
|
|
359
|
+
console.warn(
|
|
360
|
+
`\x1B[33m\u26A0 ScrapeBadger: Rate limit: ${remaining}/${limit} remaining (resets in ${resetInSec}s), throttling pagination\x1B[0m`
|
|
361
|
+
);
|
|
362
|
+
await sleep(delayMs);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
298
365
|
for (const item of response.data) {
|
|
299
366
|
yield item;
|
|
300
367
|
totalYielded++;
|
|
@@ -312,6 +379,9 @@ async function collectAll(generator) {
|
|
|
312
379
|
}
|
|
313
380
|
return items;
|
|
314
381
|
}
|
|
382
|
+
function sleep(ms) {
|
|
383
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
384
|
+
}
|
|
315
385
|
|
|
316
386
|
// src/twitter/tweets.ts
|
|
317
387
|
var TweetsClient = class {
|
|
@@ -509,7 +579,8 @@ var TweetsClient = class {
|
|
|
509
579
|
*/
|
|
510
580
|
async *getQuotesAll(tweetId, options = {}) {
|
|
511
581
|
const fetchPage = async (cursor) => {
|
|
512
|
-
|
|
582
|
+
const { data, rateLimit } = await this.client.requestWithHeaders(`/v1/twitter/tweets/tweet/${tweetId}/quotes`, { params: { cursor } });
|
|
583
|
+
return { response: createPaginatedResponse(data.data ?? [], data.next_cursor), rateLimit };
|
|
513
584
|
};
|
|
514
585
|
yield* paginate(fetchPage, options);
|
|
515
586
|
}
|
|
@@ -576,7 +647,15 @@ var TweetsClient = class {
|
|
|
576
647
|
*/
|
|
577
648
|
async *searchAll(query, options = {}) {
|
|
578
649
|
const fetchPage = async (cursor) => {
|
|
579
|
-
|
|
650
|
+
const { data, rateLimit } = await this.client.requestWithHeaders("/v1/twitter/tweets/advanced_search", {
|
|
651
|
+
params: {
|
|
652
|
+
query,
|
|
653
|
+
query_type: options.queryType ?? "Top",
|
|
654
|
+
count: options.count,
|
|
655
|
+
cursor
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
return { response: createPaginatedResponse(data.data ?? [], data.next_cursor), rateLimit };
|
|
580
659
|
};
|
|
581
660
|
yield* paginate(fetchPage, options);
|
|
582
661
|
}
|
|
@@ -620,10 +699,64 @@ var TweetsClient = class {
|
|
|
620
699
|
*/
|
|
621
700
|
async *getUserTweetsAll(username, options = {}) {
|
|
622
701
|
const fetchPage = async (cursor) => {
|
|
623
|
-
|
|
702
|
+
const { data, rateLimit } = await this.client.requestWithHeaders(`/v1/twitter/users/${username}/latest_tweets`, { params: { cursor } });
|
|
703
|
+
return { response: createPaginatedResponse(data.data ?? [], data.next_cursor), rateLimit };
|
|
624
704
|
};
|
|
625
705
|
yield* paginate(fetchPage, options);
|
|
626
706
|
}
|
|
707
|
+
/**
|
|
708
|
+
* Get the edit history of a tweet.
|
|
709
|
+
*
|
|
710
|
+
* @param tweetId - The tweet ID to get edit history for.
|
|
711
|
+
* @returns Paginated response containing tweet versions.
|
|
712
|
+
*
|
|
713
|
+
* @example
|
|
714
|
+
* ```typescript
|
|
715
|
+
* const history = await client.twitter.tweets.getEditHistory("1234567890");
|
|
716
|
+
* console.log(`${history.data.length} version(s) of this tweet`);
|
|
717
|
+
* ```
|
|
718
|
+
*/
|
|
719
|
+
async getEditHistory(tweetId) {
|
|
720
|
+
const response = await this.client.request(
|
|
721
|
+
`/v1/twitter/tweets/tweet/${tweetId}/edit_history`
|
|
722
|
+
);
|
|
723
|
+
return createPaginatedResponse(response.data ?? [], void 0);
|
|
724
|
+
}
|
|
725
|
+
/**
|
|
726
|
+
* Get community notes (Birdwatch) attached to a tweet.
|
|
727
|
+
*
|
|
728
|
+
* @param tweetId - The tweet ID to get community notes for.
|
|
729
|
+
* @returns Paginated response containing community notes.
|
|
730
|
+
*
|
|
731
|
+
* @example
|
|
732
|
+
* ```typescript
|
|
733
|
+
* const notes = await client.twitter.tweets.getCommunityNotes("1234567890");
|
|
734
|
+
* for (const note of notes.data) {
|
|
735
|
+
* console.log(note.text);
|
|
736
|
+
* }
|
|
737
|
+
* ```
|
|
738
|
+
*/
|
|
739
|
+
async getCommunityNotes(tweetId) {
|
|
740
|
+
const response = await this.client.request(
|
|
741
|
+
`/v1/twitter/tweets/tweet/${tweetId}/community_notes`
|
|
742
|
+
);
|
|
743
|
+
return createPaginatedResponse(response.data ?? [], void 0);
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Get a long-form article by its ID.
|
|
747
|
+
*
|
|
748
|
+
* @param articleId - The article ID to fetch.
|
|
749
|
+
* @returns The article data.
|
|
750
|
+
*
|
|
751
|
+
* @example
|
|
752
|
+
* ```typescript
|
|
753
|
+
* const article = await client.twitter.tweets.getArticle("abc123");
|
|
754
|
+
* console.log(`${article.title}: ${article.text?.slice(0, 100)}...`);
|
|
755
|
+
* ```
|
|
756
|
+
*/
|
|
757
|
+
async getArticle(articleId) {
|
|
758
|
+
return this.client.request(`/v1/twitter/tweets/article/${articleId}`);
|
|
759
|
+
}
|
|
627
760
|
};
|
|
628
761
|
|
|
629
762
|
// src/twitter/users.ts
|
|
@@ -730,7 +863,8 @@ var UsersClient = class {
|
|
|
730
863
|
*/
|
|
731
864
|
async *getFollowersAll(username, options = {}) {
|
|
732
865
|
const fetchPage = async (cursor) => {
|
|
733
|
-
|
|
866
|
+
const { data, rateLimit } = await this.client.requestWithHeaders(`/v1/twitter/users/${username}/followers`, { params: { cursor } });
|
|
867
|
+
return { response: createPaginatedResponse(data.data ?? [], data.next_cursor), rateLimit };
|
|
734
868
|
};
|
|
735
869
|
yield* paginate(fetchPage, options);
|
|
736
870
|
}
|
|
@@ -765,7 +899,8 @@ var UsersClient = class {
|
|
|
765
899
|
*/
|
|
766
900
|
async *getFollowingAll(username, options = {}) {
|
|
767
901
|
const fetchPage = async (cursor) => {
|
|
768
|
-
|
|
902
|
+
const { data, rateLimit } = await this.client.requestWithHeaders(`/v1/twitter/users/${username}/followings`, { params: { cursor } });
|
|
903
|
+
return { response: createPaginatedResponse(data.data ?? [], data.next_cursor), rateLimit };
|
|
769
904
|
};
|
|
770
905
|
yield* paginate(fetchPage, options);
|
|
771
906
|
}
|
|
@@ -928,10 +1063,97 @@ var UsersClient = class {
|
|
|
928
1063
|
*/
|
|
929
1064
|
async *searchAll(query, options = {}) {
|
|
930
1065
|
const fetchPage = async (cursor) => {
|
|
931
|
-
|
|
1066
|
+
const { data, rateLimit } = await this.client.requestWithHeaders("/v1/twitter/users/search_users", { params: { query, cursor } });
|
|
1067
|
+
return { response: createPaginatedResponse(data.data ?? [], data.next_cursor), rateLimit };
|
|
932
1068
|
};
|
|
933
1069
|
yield* paginate(fetchPage, options);
|
|
934
1070
|
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Get multiple users by their numeric IDs in a single request.
|
|
1073
|
+
*
|
|
1074
|
+
* @param userIds - List of user IDs to fetch.
|
|
1075
|
+
* @returns Paginated response containing the matching users.
|
|
1076
|
+
*
|
|
1077
|
+
* @example
|
|
1078
|
+
* ```typescript
|
|
1079
|
+
* const users = await client.twitter.users.getByIds(["44196397", "783214"]);
|
|
1080
|
+
* for (const user of users.data) {
|
|
1081
|
+
* console.log(`@${user.username}`);
|
|
1082
|
+
* }
|
|
1083
|
+
* ```
|
|
1084
|
+
*/
|
|
1085
|
+
async getByIds(userIds) {
|
|
1086
|
+
const response = await this.client.request(
|
|
1087
|
+
"/v1/twitter/users/batch_by_ids",
|
|
1088
|
+
{ params: { user_ids: userIds.join(",") } }
|
|
1089
|
+
);
|
|
1090
|
+
return createPaginatedResponse(response.data ?? [], void 0);
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Get multiple users by their usernames in a single request.
|
|
1094
|
+
*
|
|
1095
|
+
* @param usernames - List of usernames (without @) to fetch.
|
|
1096
|
+
* @returns Paginated response containing the matching users.
|
|
1097
|
+
*
|
|
1098
|
+
* @example
|
|
1099
|
+
* ```typescript
|
|
1100
|
+
* const users = await client.twitter.users.getByUsernames(["elonmusk", "twitter"]);
|
|
1101
|
+
* for (const user of users.data) {
|
|
1102
|
+
* console.log(`${user.name}: ${user.followers_count?.toLocaleString()} followers`);
|
|
1103
|
+
* }
|
|
1104
|
+
* ```
|
|
1105
|
+
*/
|
|
1106
|
+
async getByUsernames(usernames) {
|
|
1107
|
+
const response = await this.client.request(
|
|
1108
|
+
"/v1/twitter/users/batch_by_usernames",
|
|
1109
|
+
{ params: { usernames: usernames.join(",") } }
|
|
1110
|
+
);
|
|
1111
|
+
return createPaginatedResponse(response.data ?? [], void 0);
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* Get tweets that mention a user.
|
|
1115
|
+
*
|
|
1116
|
+
* @param username - The user's username (without @).
|
|
1117
|
+
* @param options - Pagination options with optional count.
|
|
1118
|
+
* @returns Paginated response containing tweets mentioning the user.
|
|
1119
|
+
*
|
|
1120
|
+
* @example
|
|
1121
|
+
* ```typescript
|
|
1122
|
+
* const mentions = await client.twitter.users.getMentions("elonmusk");
|
|
1123
|
+
* for (const tweet of mentions.data) {
|
|
1124
|
+
* console.log(`@${tweet.username}: ${tweet.text.slice(0, 100)}...`);
|
|
1125
|
+
* }
|
|
1126
|
+
* ```
|
|
1127
|
+
*/
|
|
1128
|
+
async getMentions(username, options = {}) {
|
|
1129
|
+
const response = await this.client.request(
|
|
1130
|
+
`/v1/twitter/users/${username}/mentions`,
|
|
1131
|
+
{ params: { count: options.count, cursor: options.cursor } }
|
|
1132
|
+
);
|
|
1133
|
+
return createPaginatedResponse(response.data ?? [], response.next_cursor);
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Get long-form articles authored by a user.
|
|
1137
|
+
*
|
|
1138
|
+
* @param userId - The user's numeric ID.
|
|
1139
|
+
* @param options - Pagination options with optional count.
|
|
1140
|
+
* @returns Paginated response containing the user's articles as tweets.
|
|
1141
|
+
*
|
|
1142
|
+
* @example
|
|
1143
|
+
* ```typescript
|
|
1144
|
+
* const articles = await client.twitter.users.getArticles("44196397");
|
|
1145
|
+
* for (const article of articles.data) {
|
|
1146
|
+
* console.log(article.text?.slice(0, 100));
|
|
1147
|
+
* }
|
|
1148
|
+
* ```
|
|
1149
|
+
*/
|
|
1150
|
+
async getArticles(userId, options = {}) {
|
|
1151
|
+
const response = await this.client.request(
|
|
1152
|
+
`/v1/twitter/users/${userId}/articles`,
|
|
1153
|
+
{ params: { count: options.count, cursor: options.cursor } }
|
|
1154
|
+
);
|
|
1155
|
+
return createPaginatedResponse(response.data ?? [], response.next_cursor);
|
|
1156
|
+
}
|
|
935
1157
|
};
|
|
936
1158
|
|
|
937
1159
|
// src/twitter/lists.ts
|
|
@@ -988,7 +1210,8 @@ var ListsClient = class {
|
|
|
988
1210
|
*/
|
|
989
1211
|
async *getTweetsAll(listId, options = {}) {
|
|
990
1212
|
const fetchPage = async (cursor) => {
|
|
991
|
-
|
|
1213
|
+
const { data, rateLimit } = await this.client.requestWithHeaders(`/v1/twitter/lists/${listId}/tweets`, { params: { cursor } });
|
|
1214
|
+
return { response: createPaginatedResponse(data.data ?? [], data.next_cursor), rateLimit };
|
|
992
1215
|
};
|
|
993
1216
|
yield* paginate(fetchPage, options);
|
|
994
1217
|
}
|
|
@@ -1023,7 +1246,8 @@ var ListsClient = class {
|
|
|
1023
1246
|
*/
|
|
1024
1247
|
async *getMembersAll(listId, options = {}) {
|
|
1025
1248
|
const fetchPage = async (cursor) => {
|
|
1026
|
-
|
|
1249
|
+
const { data, rateLimit } = await this.client.requestWithHeaders(`/v1/twitter/lists/${listId}/members`, { params: { cursor } });
|
|
1250
|
+
return { response: createPaginatedResponse(data.data ?? [], data.next_cursor), rateLimit };
|
|
1027
1251
|
};
|
|
1028
1252
|
yield* paginate(fetchPage, options);
|
|
1029
1253
|
}
|
|
@@ -1076,6 +1300,29 @@ var ListsClient = class {
|
|
|
1076
1300
|
);
|
|
1077
1301
|
return createPaginatedResponse(response.data ?? [], response.next_cursor);
|
|
1078
1302
|
}
|
|
1303
|
+
/**
|
|
1304
|
+
* Search tweets within a specific list.
|
|
1305
|
+
*
|
|
1306
|
+
* @param listId - The list ID to search within.
|
|
1307
|
+
* @param query - Search query string.
|
|
1308
|
+
* @param options - Pagination options with optional count.
|
|
1309
|
+
* @returns Paginated response containing matching tweets from the list.
|
|
1310
|
+
*
|
|
1311
|
+
* @example
|
|
1312
|
+
* ```typescript
|
|
1313
|
+
* const results = await client.twitter.lists.searchTweets("123456", "python");
|
|
1314
|
+
* for (const tweet of results.data) {
|
|
1315
|
+
* console.log(`@${tweet.username}: ${tweet.text.slice(0, 100)}...`);
|
|
1316
|
+
* }
|
|
1317
|
+
* ```
|
|
1318
|
+
*/
|
|
1319
|
+
async searchTweets(listId, query, options = {}) {
|
|
1320
|
+
const response = await this.client.request(
|
|
1321
|
+
`/v1/twitter/lists/${listId}/search_tweets`,
|
|
1322
|
+
{ params: { query, count: options.count, cursor: options.cursor } }
|
|
1323
|
+
);
|
|
1324
|
+
return createPaginatedResponse(response.data ?? [], response.next_cursor);
|
|
1325
|
+
}
|
|
1079
1326
|
};
|
|
1080
1327
|
|
|
1081
1328
|
// src/twitter/communities.ts
|
|
@@ -1171,7 +1418,14 @@ var CommunitiesClient = class {
|
|
|
1171
1418
|
*/
|
|
1172
1419
|
async *getTweetsAll(communityId, options = {}) {
|
|
1173
1420
|
const fetchPage = async (cursor) => {
|
|
1174
|
-
|
|
1421
|
+
const { data, rateLimit } = await this.client.requestWithHeaders(`/v1/twitter/communities/${communityId}/tweets`, {
|
|
1422
|
+
params: {
|
|
1423
|
+
tweet_type: options.tweetType ?? "Top",
|
|
1424
|
+
count: options.count ?? 40,
|
|
1425
|
+
cursor
|
|
1426
|
+
}
|
|
1427
|
+
});
|
|
1428
|
+
return { response: createPaginatedResponse(data.data ?? [], data.next_cursor), rateLimit };
|
|
1175
1429
|
};
|
|
1176
1430
|
yield* paginate(fetchPage, options);
|
|
1177
1431
|
}
|
|
@@ -2090,6 +2344,46 @@ function verifyWebhookSignature(secret, body, signatureHeader) {
|
|
|
2090
2344
|
}
|
|
2091
2345
|
}
|
|
2092
2346
|
|
|
2347
|
+
// src/twitter/spaces.ts
|
|
2348
|
+
var SpacesClient = class {
|
|
2349
|
+
client;
|
|
2350
|
+
constructor(client) {
|
|
2351
|
+
this.client = client;
|
|
2352
|
+
}
|
|
2353
|
+
/**
|
|
2354
|
+
* Get details for a specific Twitter Space.
|
|
2355
|
+
*
|
|
2356
|
+
* @param spaceId - The Space ID to fetch.
|
|
2357
|
+
* @returns The Space data.
|
|
2358
|
+
* @throws NotFoundError - If the Space doesn't exist.
|
|
2359
|
+
*
|
|
2360
|
+
* @example
|
|
2361
|
+
* ```typescript
|
|
2362
|
+
* const space = await client.twitter.spaces.getDetail("1eaKbrPPbPwKX");
|
|
2363
|
+
* console.log(`${space.title} — ${space.participant_count} participants`);
|
|
2364
|
+
* ```
|
|
2365
|
+
*/
|
|
2366
|
+
async getDetail(spaceId) {
|
|
2367
|
+
return this.client.request(`/v1/twitter/spaces/${spaceId}`);
|
|
2368
|
+
}
|
|
2369
|
+
/**
|
|
2370
|
+
* Get details for a live video broadcast.
|
|
2371
|
+
*
|
|
2372
|
+
* @param broadcastId - The broadcast ID to fetch.
|
|
2373
|
+
* @returns The broadcast data.
|
|
2374
|
+
* @throws NotFoundError - If the broadcast doesn't exist.
|
|
2375
|
+
*
|
|
2376
|
+
* @example
|
|
2377
|
+
* ```typescript
|
|
2378
|
+
* const broadcast = await client.twitter.spaces.getBroadcast("broadcast123");
|
|
2379
|
+
* console.log(`${broadcast.title}: ${broadcast.total_viewers} viewers`);
|
|
2380
|
+
* ```
|
|
2381
|
+
*/
|
|
2382
|
+
async getBroadcast(broadcastId) {
|
|
2383
|
+
return this.client.request(`/v1/twitter/spaces/broadcast/${broadcastId}`);
|
|
2384
|
+
}
|
|
2385
|
+
};
|
|
2386
|
+
|
|
2093
2387
|
// src/twitter/client.ts
|
|
2094
2388
|
var TwitterClient = class {
|
|
2095
2389
|
/** Client for tweet operations */
|
|
@@ -2106,6 +2400,8 @@ var TwitterClient = class {
|
|
|
2106
2400
|
geo;
|
|
2107
2401
|
/** Client for real-time stream monitor management and WebSocket streaming */
|
|
2108
2402
|
stream;
|
|
2403
|
+
/** Client for Twitter Spaces and live broadcast operations */
|
|
2404
|
+
spaces;
|
|
2109
2405
|
/**
|
|
2110
2406
|
* Create a new Twitter client.
|
|
2111
2407
|
*
|
|
@@ -2119,6 +2415,7 @@ var TwitterClient = class {
|
|
|
2119
2415
|
this.trends = new TrendsClient(client);
|
|
2120
2416
|
this.geo = new GeoClient(client);
|
|
2121
2417
|
this.stream = new StreamClient(client);
|
|
2418
|
+
this.spaces = new SpacesClient(client);
|
|
2122
2419
|
}
|
|
2123
2420
|
};
|
|
2124
2421
|
|
|
@@ -2267,6 +2564,6 @@ var ScrapeBadger = class {
|
|
|
2267
2564
|
}
|
|
2268
2565
|
};
|
|
2269
2566
|
|
|
2270
|
-
export { AccountRestrictedError, AuthenticationError, CommunitiesClient, ConflictError, GeoClient, InsufficientCreditsError, ListsClient, NotFoundError, RateLimitError, ScrapeBadger, ScrapeBadgerError, ServerError, StreamClient, TimeoutError, TrendsClient, TweetsClient, TwitterClient, UsersClient, ValidationError, WebClient, WebSocketStreamError, collectAll, verifyWebhookSignature };
|
|
2567
|
+
export { AccountRestrictedError, AuthenticationError, CommunitiesClient, ConflictError, GeoClient, InsufficientCreditsError, ListsClient, NotFoundError, RateLimitError, ScrapeBadger, ScrapeBadgerError, ServerError, SpacesClient, StreamClient, TimeoutError, TrendsClient, TweetsClient, TwitterClient, UsersClient, ValidationError, WebClient, WebSocketStreamError, collectAll, verifyWebhookSignature };
|
|
2271
2568
|
//# sourceMappingURL=index.mjs.map
|
|
2272
2569
|
//# sourceMappingURL=index.mjs.map
|