@spectratools/xapi-cli 0.3.0 → 0.5.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/dist/cli.js +191 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -189,6 +189,15 @@ function createXApiClient(bearerToken) {
|
|
|
189
189
|
function likePost(userId, tweetId) {
|
|
190
190
|
return post(`/users/${userId}/likes`, { tweet_id: tweetId });
|
|
191
191
|
}
|
|
192
|
+
function unlikePost(userId, tweetId) {
|
|
193
|
+
return del(`/users/${userId}/likes/${tweetId}`);
|
|
194
|
+
}
|
|
195
|
+
function bookmarkPost(userId, tweetId) {
|
|
196
|
+
return post(`/users/${userId}/bookmarks`, { tweet_id: tweetId });
|
|
197
|
+
}
|
|
198
|
+
function unbookmarkPost(userId, tweetId) {
|
|
199
|
+
return del(`/users/${userId}/bookmarks/${tweetId}`);
|
|
200
|
+
}
|
|
192
201
|
function retweetPost(userId, tweetId) {
|
|
193
202
|
return post(`/users/${userId}/retweets`, { tweet_id: tweetId });
|
|
194
203
|
}
|
|
@@ -225,6 +234,22 @@ function createXApiClient(bearerToken) {
|
|
|
225
234
|
function unfollowUser(sourceUserId, targetUserId) {
|
|
226
235
|
return del(`/users/${sourceUserId}/following/${targetUserId}`);
|
|
227
236
|
}
|
|
237
|
+
function blockUser(sourceUserId, targetUserId) {
|
|
238
|
+
return post(`/users/${sourceUserId}/blocking`, {
|
|
239
|
+
target_user_id: targetUserId
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function unblockUser(sourceUserId, targetUserId) {
|
|
243
|
+
return del(`/users/${sourceUserId}/blocking/${targetUserId}`);
|
|
244
|
+
}
|
|
245
|
+
function muteUser(sourceUserId, targetUserId) {
|
|
246
|
+
return post(`/users/${sourceUserId}/muting`, {
|
|
247
|
+
target_user_id: targetUserId
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function unmuteUser(sourceUserId, targetUserId) {
|
|
251
|
+
return del(`/users/${sourceUserId}/muting/${targetUserId}`);
|
|
252
|
+
}
|
|
228
253
|
function getUserPosts(id, maxResults, nextToken) {
|
|
229
254
|
return get(`/users/${id}/tweets`, {
|
|
230
255
|
max_results: maxResults,
|
|
@@ -280,6 +305,24 @@ function createXApiClient(bearerToken) {
|
|
|
280
305
|
...nextToken ? { pagination_token: nextToken } : {}
|
|
281
306
|
});
|
|
282
307
|
}
|
|
308
|
+
function createList(name, description, isPrivate) {
|
|
309
|
+
return post("/lists", {
|
|
310
|
+
name,
|
|
311
|
+
...description ? { description } : {},
|
|
312
|
+
...isPrivate !== void 0 ? { private: isPrivate } : {}
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
function deleteList(id) {
|
|
316
|
+
return del(`/lists/${id}`);
|
|
317
|
+
}
|
|
318
|
+
function addListMember(id, userId) {
|
|
319
|
+
return post(`/lists/${id}/members`, {
|
|
320
|
+
user_id: userId
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
function removeListMember(id, userId) {
|
|
324
|
+
return del(`/lists/${id}/members/${userId}`);
|
|
325
|
+
}
|
|
283
326
|
function getTrendingPlaces() {
|
|
284
327
|
return getV1_1(
|
|
285
328
|
"/trends/available.json"
|
|
@@ -318,6 +361,9 @@ function createXApiClient(bearerToken) {
|
|
|
318
361
|
getPostLikes,
|
|
319
362
|
getPostRetweets,
|
|
320
363
|
likePost,
|
|
364
|
+
unlikePost,
|
|
365
|
+
bookmarkPost,
|
|
366
|
+
unbookmarkPost,
|
|
321
367
|
retweetPost,
|
|
322
368
|
getUserByUsername,
|
|
323
369
|
getUserById,
|
|
@@ -325,6 +371,10 @@ function createXApiClient(bearerToken) {
|
|
|
325
371
|
getUserFollowing,
|
|
326
372
|
followUser,
|
|
327
373
|
unfollowUser,
|
|
374
|
+
blockUser,
|
|
375
|
+
unblockUser,
|
|
376
|
+
muteUser,
|
|
377
|
+
unmuteUser,
|
|
328
378
|
getUserPosts,
|
|
329
379
|
getUserMentions,
|
|
330
380
|
searchUsers,
|
|
@@ -333,6 +383,10 @@ function createXApiClient(bearerToken) {
|
|
|
333
383
|
getList,
|
|
334
384
|
getListMembers,
|
|
335
385
|
getListPosts,
|
|
386
|
+
createList,
|
|
387
|
+
deleteList,
|
|
388
|
+
addListMember,
|
|
389
|
+
removeListMember,
|
|
336
390
|
getTrendingPlaces,
|
|
337
391
|
getTrendsByLocation,
|
|
338
392
|
getDmConversations,
|
|
@@ -791,6 +845,54 @@ posts.command("delete", {
|
|
|
791
845
|
}
|
|
792
846
|
}
|
|
793
847
|
});
|
|
848
|
+
posts.command("like", {
|
|
849
|
+
description: "Like a post by ID.",
|
|
850
|
+
args: z4.object({
|
|
851
|
+
id: z4.string().describe("Post ID to like")
|
|
852
|
+
}),
|
|
853
|
+
env: xApiWriteEnv,
|
|
854
|
+
output: z4.object({
|
|
855
|
+
liked: z4.boolean(),
|
|
856
|
+
id: z4.string()
|
|
857
|
+
}),
|
|
858
|
+
examples: [{ args: { id: "1234567890" }, description: "Like a post" }],
|
|
859
|
+
async run(c) {
|
|
860
|
+
try {
|
|
861
|
+
const client = createXApiClient(writeAuthToken(c.env));
|
|
862
|
+
const me = await client.getMe();
|
|
863
|
+
const res = await client.likePost(me.data.id, c.args.id);
|
|
864
|
+
return c.ok({ liked: res.data.liked, id: c.args.id });
|
|
865
|
+
} catch (error) {
|
|
866
|
+
const authError = toWriteAuthError("posts like", error);
|
|
867
|
+
if (authError) return c.error(authError);
|
|
868
|
+
throw error;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
});
|
|
872
|
+
posts.command("retweet", {
|
|
873
|
+
description: "Retweet a post by ID.",
|
|
874
|
+
args: z4.object({
|
|
875
|
+
id: z4.string().describe("Post ID to retweet")
|
|
876
|
+
}),
|
|
877
|
+
env: xApiWriteEnv,
|
|
878
|
+
output: z4.object({
|
|
879
|
+
retweeted: z4.boolean(),
|
|
880
|
+
id: z4.string()
|
|
881
|
+
}),
|
|
882
|
+
examples: [{ args: { id: "1234567890" }, description: "Retweet a post" }],
|
|
883
|
+
async run(c) {
|
|
884
|
+
try {
|
|
885
|
+
const client = createXApiClient(writeAuthToken(c.env));
|
|
886
|
+
const me = await client.getMe();
|
|
887
|
+
const res = await client.retweetPost(me.data.id, c.args.id);
|
|
888
|
+
return c.ok({ retweeted: res.data.retweeted, id: c.args.id });
|
|
889
|
+
} catch (error) {
|
|
890
|
+
const authError = toWriteAuthError("posts retweet", error);
|
|
891
|
+
if (authError) return c.error(authError);
|
|
892
|
+
throw error;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
});
|
|
794
896
|
posts.command("likes", {
|
|
795
897
|
description: "List users who liked a post.",
|
|
796
898
|
args: z4.object({
|
|
@@ -887,6 +989,7 @@ timeline.command("home", {
|
|
|
887
989
|
description: "View your home timeline.",
|
|
888
990
|
options: z5.object({
|
|
889
991
|
maxResults: z5.number().default(25).describe("Maximum posts to return (5\u2013100)"),
|
|
992
|
+
sinceId: z5.string().optional().describe("Only return posts newer than this post ID"),
|
|
890
993
|
verbose: z5.boolean().optional().describe("Show full text without truncation")
|
|
891
994
|
}),
|
|
892
995
|
alias: { maxResults: "n" },
|
|
@@ -906,14 +1009,18 @@ timeline.command("home", {
|
|
|
906
1009
|
}),
|
|
907
1010
|
examples: [
|
|
908
1011
|
{ description: "View your home timeline" },
|
|
909
|
-
{ options: { maxResults: 50 }, description: "View 50 posts" }
|
|
1012
|
+
{ options: { maxResults: 50 }, description: "View 50 posts" },
|
|
1013
|
+
{
|
|
1014
|
+
options: { sinceId: "1900123456789012345" },
|
|
1015
|
+
description: "Resume from last-seen post ID"
|
|
1016
|
+
}
|
|
910
1017
|
],
|
|
911
1018
|
async run(c) {
|
|
912
1019
|
const client = createXApiClient(readAuthToken(c.env));
|
|
913
1020
|
const meRes = await client.getMe();
|
|
914
1021
|
const userId = meRes.data.id;
|
|
915
1022
|
const allPosts = await collectPaged(
|
|
916
|
-
(limit, cursor) => client.getHomeTimeline(userId, limit, cursor),
|
|
1023
|
+
(limit, cursor) => client.getHomeTimeline(userId, limit, cursor, c.options.sinceId),
|
|
917
1024
|
(post) => ({
|
|
918
1025
|
id: post.id,
|
|
919
1026
|
text: c.options.verbose ? post.text : truncateText(post.text),
|
|
@@ -946,6 +1053,7 @@ timeline.command("mentions", {
|
|
|
946
1053
|
description: "View your recent mentions.",
|
|
947
1054
|
options: z5.object({
|
|
948
1055
|
maxResults: z5.number().default(25).describe("Maximum mentions to return"),
|
|
1056
|
+
sinceId: z5.string().optional().describe("Only return mentions newer than this post ID"),
|
|
949
1057
|
verbose: z5.boolean().optional().describe("Show full text without truncation")
|
|
950
1058
|
}),
|
|
951
1059
|
alias: { maxResults: "n" },
|
|
@@ -961,13 +1069,19 @@ timeline.command("mentions", {
|
|
|
961
1069
|
),
|
|
962
1070
|
count: z5.number()
|
|
963
1071
|
}),
|
|
964
|
-
examples: [
|
|
1072
|
+
examples: [
|
|
1073
|
+
{ description: "View your recent mentions" },
|
|
1074
|
+
{
|
|
1075
|
+
options: { sinceId: "1900123456789012345" },
|
|
1076
|
+
description: "Resume mentions from last-seen post ID"
|
|
1077
|
+
}
|
|
1078
|
+
],
|
|
965
1079
|
async run(c) {
|
|
966
1080
|
const client = createXApiClient(readAuthToken(c.env));
|
|
967
1081
|
const meRes = await client.getMe();
|
|
968
1082
|
const userId = meRes.data.id;
|
|
969
1083
|
const allPosts = await collectPaged(
|
|
970
|
-
(limit, cursor) => client.getMentionsTimeline(userId, limit, cursor),
|
|
1084
|
+
(limit, cursor) => client.getMentionsTimeline(userId, limit, cursor, c.options.sinceId),
|
|
971
1085
|
(post) => ({
|
|
972
1086
|
id: post.id,
|
|
973
1087
|
text: c.options.verbose ? post.text : truncateText(post.text),
|
|
@@ -1198,6 +1312,70 @@ users.command("get", {
|
|
|
1198
1312
|
);
|
|
1199
1313
|
}
|
|
1200
1314
|
});
|
|
1315
|
+
users.command("follow", {
|
|
1316
|
+
description: "Follow a user by username or ID.",
|
|
1317
|
+
args: z7.object({
|
|
1318
|
+
username: z7.string().describe("Username (with or without @) or user ID")
|
|
1319
|
+
}),
|
|
1320
|
+
env: xApiWriteEnv,
|
|
1321
|
+
output: z7.object({
|
|
1322
|
+
id: z7.string(),
|
|
1323
|
+
username: z7.string(),
|
|
1324
|
+
following: z7.boolean(),
|
|
1325
|
+
pending_follow: z7.boolean().optional()
|
|
1326
|
+
}),
|
|
1327
|
+
examples: [{ args: { username: "jack" }, description: "Follow @jack" }],
|
|
1328
|
+
async run(c) {
|
|
1329
|
+
try {
|
|
1330
|
+
const client = createXApiClient(writeAuthToken(c.env));
|
|
1331
|
+
const me = await client.getMe();
|
|
1332
|
+
const targetRes = await resolveUser(client, c.args.username);
|
|
1333
|
+
const target = targetRes.data;
|
|
1334
|
+
const res = await client.followUser(me.data.id, target.id);
|
|
1335
|
+
return c.ok({
|
|
1336
|
+
id: target.id,
|
|
1337
|
+
username: target.username,
|
|
1338
|
+
following: res.data.following,
|
|
1339
|
+
pending_follow: res.data.pending_follow
|
|
1340
|
+
});
|
|
1341
|
+
} catch (error) {
|
|
1342
|
+
const authError = toWriteAuthError("users follow", error);
|
|
1343
|
+
if (authError) return c.error(authError);
|
|
1344
|
+
throw error;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
});
|
|
1348
|
+
users.command("unfollow", {
|
|
1349
|
+
description: "Unfollow a user by username or ID.",
|
|
1350
|
+
args: z7.object({
|
|
1351
|
+
username: z7.string().describe("Username (with or without @) or user ID")
|
|
1352
|
+
}),
|
|
1353
|
+
env: xApiWriteEnv,
|
|
1354
|
+
output: z7.object({
|
|
1355
|
+
id: z7.string(),
|
|
1356
|
+
username: z7.string(),
|
|
1357
|
+
following: z7.boolean()
|
|
1358
|
+
}),
|
|
1359
|
+
examples: [{ args: { username: "jack" }, description: "Unfollow @jack" }],
|
|
1360
|
+
async run(c) {
|
|
1361
|
+
try {
|
|
1362
|
+
const client = createXApiClient(writeAuthToken(c.env));
|
|
1363
|
+
const me = await client.getMe();
|
|
1364
|
+
const targetRes = await resolveUser(client, c.args.username);
|
|
1365
|
+
const target = targetRes.data;
|
|
1366
|
+
const res = await client.unfollowUser(me.data.id, target.id);
|
|
1367
|
+
return c.ok({
|
|
1368
|
+
id: target.id,
|
|
1369
|
+
username: target.username,
|
|
1370
|
+
following: res.data.following
|
|
1371
|
+
});
|
|
1372
|
+
} catch (error) {
|
|
1373
|
+
const authError = toWriteAuthError("users unfollow", error);
|
|
1374
|
+
if (authError) return c.error(authError);
|
|
1375
|
+
throw error;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
});
|
|
1201
1379
|
users.command("followers", {
|
|
1202
1380
|
description: "List followers of a user. Supports optional client-side baseline diffing for new follower detection.",
|
|
1203
1381
|
args: z7.object({
|
|
@@ -1439,7 +1617,15 @@ var cli = Cli7.create("xapi", {
|
|
|
1439
1617
|
version: pkg.version,
|
|
1440
1618
|
description: "X (Twitter) API CLI for spectra-the-bot."
|
|
1441
1619
|
});
|
|
1442
|
-
var WRITE_OPERATIONS = /* @__PURE__ */ new Set([
|
|
1620
|
+
var WRITE_OPERATIONS = /* @__PURE__ */ new Set([
|
|
1621
|
+
"posts create",
|
|
1622
|
+
"posts delete",
|
|
1623
|
+
"posts like",
|
|
1624
|
+
"posts retweet",
|
|
1625
|
+
"users follow",
|
|
1626
|
+
"users unfollow",
|
|
1627
|
+
"dm send"
|
|
1628
|
+
]);
|
|
1443
1629
|
cli.use(async ({ command, error }, next) => {
|
|
1444
1630
|
try {
|
|
1445
1631
|
return await next();
|