@dotta/xc 0.1.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 +348 -0
- package/dist/__tests__/bookmarks.test.d.ts +4 -0
- package/dist/__tests__/bookmarks.test.js +104 -0
- package/dist/__tests__/bookmarks.test.js.map +1 -0
- package/dist/__tests__/budget.test.d.ts +6 -0
- package/dist/__tests__/budget.test.js +105 -0
- package/dist/__tests__/budget.test.js.map +1 -0
- package/dist/__tests__/dm.test.d.ts +4 -0
- package/dist/__tests__/dm.test.js +115 -0
- package/dist/__tests__/dm.test.js.map +1 -0
- package/dist/__tests__/followers.test.d.ts +4 -0
- package/dist/__tests__/followers.test.js +129 -0
- package/dist/__tests__/followers.test.js.map +1 -0
- package/dist/__tests__/lib/api.test.d.ts +5 -0
- package/dist/__tests__/lib/api.test.js +202 -0
- package/dist/__tests__/lib/api.test.js.map +1 -0
- package/dist/__tests__/lib/budget.test.d.ts +5 -0
- package/dist/__tests__/lib/budget.test.js +194 -0
- package/dist/__tests__/lib/budget.test.js.map +1 -0
- package/dist/__tests__/lib/config.test.d.ts +6 -0
- package/dist/__tests__/lib/config.test.js +228 -0
- package/dist/__tests__/lib/config.test.js.map +1 -0
- package/dist/__tests__/lib/cost.test.d.ts +6 -0
- package/dist/__tests__/lib/cost.test.js +177 -0
- package/dist/__tests__/lib/cost.test.js.map +1 -0
- package/dist/__tests__/lib/format.test.d.ts +4 -0
- package/dist/__tests__/lib/format.test.js +139 -0
- package/dist/__tests__/lib/format.test.js.map +1 -0
- package/dist/__tests__/lib/oauth.test.d.ts +5 -0
- package/dist/__tests__/lib/oauth.test.js +123 -0
- package/dist/__tests__/lib/oauth.test.js.map +1 -0
- package/dist/__tests__/lib/resolve.test.d.ts +4 -0
- package/dist/__tests__/lib/resolve.test.js +154 -0
- package/dist/__tests__/lib/resolve.test.js.map +1 -0
- package/dist/__tests__/lists.test.d.ts +4 -0
- package/dist/__tests__/lists.test.js +96 -0
- package/dist/__tests__/lists.test.js.map +1 -0
- package/dist/__tests__/media.test.d.ts +4 -0
- package/dist/__tests__/media.test.js +132 -0
- package/dist/__tests__/media.test.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +93 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +191 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/block.d.ts +15 -0
- package/dist/commands/block.js +117 -0
- package/dist/commands/block.js.map +1 -0
- package/dist/commands/bookmarks.d.ts +12 -0
- package/dist/commands/bookmarks.js +100 -0
- package/dist/commands/bookmarks.js.map +1 -0
- package/dist/commands/budget.d.ts +9 -0
- package/dist/commands/budget.js +124 -0
- package/dist/commands/budget.js.map +1 -0
- package/dist/commands/cost.d.ts +5 -0
- package/dist/commands/cost.js +75 -0
- package/dist/commands/cost.js.map +1 -0
- package/dist/commands/delete.d.ts +8 -0
- package/dist/commands/delete.js +31 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/dm.d.ts +10 -0
- package/dist/commands/dm.js +179 -0
- package/dist/commands/dm.js.map +1 -0
- package/dist/commands/engagement.d.ts +14 -0
- package/dist/commands/engagement.js +167 -0
- package/dist/commands/engagement.js.map +1 -0
- package/dist/commands/followers.d.ts +14 -0
- package/dist/commands/followers.js +138 -0
- package/dist/commands/followers.js.map +1 -0
- package/dist/commands/get.d.ts +2 -0
- package/dist/commands/get.js +63 -0
- package/dist/commands/get.js.map +1 -0
- package/dist/commands/hide.d.ts +10 -0
- package/dist/commands/hide.js +58 -0
- package/dist/commands/hide.js.map +1 -0
- package/dist/commands/like.d.ts +3 -0
- package/dist/commands/like.js +52 -0
- package/dist/commands/like.js.map +1 -0
- package/dist/commands/lists.d.ts +20 -0
- package/dist/commands/lists.js +384 -0
- package/dist/commands/lists.js.map +1 -0
- package/dist/commands/media.d.ts +19 -0
- package/dist/commands/media.js +205 -0
- package/dist/commands/media.js.map +1 -0
- package/dist/commands/mentions.d.ts +8 -0
- package/dist/commands/mentions.js +59 -0
- package/dist/commands/mentions.js.map +1 -0
- package/dist/commands/mute.d.ts +12 -0
- package/dist/commands/mute.js +99 -0
- package/dist/commands/mute.js.map +1 -0
- package/dist/commands/post.d.ts +11 -0
- package/dist/commands/post.js +87 -0
- package/dist/commands/post.js.map +1 -0
- package/dist/commands/repost.d.ts +10 -0
- package/dist/commands/repost.js +59 -0
- package/dist/commands/repost.js.map +1 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +49 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/stream.d.ts +13 -0
- package/dist/commands/stream.js +251 -0
- package/dist/commands/stream.js.map +1 -0
- package/dist/commands/timeline.d.ts +2 -0
- package/dist/commands/timeline.js +61 -0
- package/dist/commands/timeline.js.map +1 -0
- package/dist/commands/trends.d.ts +10 -0
- package/dist/commands/trends.js +59 -0
- package/dist/commands/trends.js.map +1 -0
- package/dist/commands/usage.d.ts +2 -0
- package/dist/commands/usage.js +52 -0
- package/dist/commands/usage.js.map +1 -0
- package/dist/commands/user.d.ts +2 -0
- package/dist/commands/user.js +43 -0
- package/dist/commands/user.js.map +1 -0
- package/dist/commands/usersearch.d.ts +8 -0
- package/dist/commands/usersearch.js +48 -0
- package/dist/commands/usersearch.js.map +1 -0
- package/dist/commands/whoami.d.ts +2 -0
- package/dist/commands/whoami.js +54 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/lib/api.d.ts +12 -0
- package/dist/lib/api.js +91 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/budget.d.ts +44 -0
- package/dist/lib/budget.js +119 -0
- package/dist/lib/budget.js.map +1 -0
- package/dist/lib/config.d.ts +39 -0
- package/dist/lib/config.js +63 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/cost.d.ts +43 -0
- package/dist/lib/cost.js +224 -0
- package/dist/lib/cost.js.map +1 -0
- package/dist/lib/format.d.ts +24 -0
- package/dist/lib/format.js +72 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/oauth.d.ts +32 -0
- package/dist/lib/oauth.js +132 -0
- package/dist/lib/oauth.js.map +1 -0
- package/dist/lib/resolve.d.ts +12 -0
- package/dist/lib/resolve.js +48 -0
- package/dist/lib/resolve.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream commands: manage filtered stream rules and connect to the stream.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* xc stream add <query> [--tag <name>] โ add a filtered stream rule
|
|
6
|
+
* xc stream rules โ list current rules
|
|
7
|
+
* xc stream remove <rule-id> โ remove a rule by ID
|
|
8
|
+
* xc stream clear โ remove all rules
|
|
9
|
+
* xc stream connect [--json] [--quiet] โ connect and output matching posts
|
|
10
|
+
*/
|
|
11
|
+
import { getClient } from "../lib/api.js";
|
|
12
|
+
import { outputJson } from "../lib/cost.js";
|
|
13
|
+
/** Register the `stream` command group with its subcommands. */
|
|
14
|
+
export function registerStreamCommand(program) {
|
|
15
|
+
const stream = program
|
|
16
|
+
.command("stream")
|
|
17
|
+
.description("Manage filtered stream rules and connect");
|
|
18
|
+
// --- stream add <query> ---
|
|
19
|
+
stream
|
|
20
|
+
.command("add <query>")
|
|
21
|
+
.description("Add a filtered stream rule")
|
|
22
|
+
.option("--tag <name>", "Label for this rule")
|
|
23
|
+
.option("--account <name>", "Account to use")
|
|
24
|
+
.option("--json", "Output raw JSON")
|
|
25
|
+
.action(async (query, opts) => {
|
|
26
|
+
try {
|
|
27
|
+
const client = await getClient(opts.account);
|
|
28
|
+
// Build the add-rules request body
|
|
29
|
+
const rule = { value: query };
|
|
30
|
+
if (opts.tag)
|
|
31
|
+
rule.tag = opts.tag;
|
|
32
|
+
const result = await client.stream.updateRules({ add: [rule] });
|
|
33
|
+
if (opts.json) {
|
|
34
|
+
outputJson(result);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const rules = result.data ?? [];
|
|
38
|
+
if (rules.length > 0) {
|
|
39
|
+
for (const r of rules) {
|
|
40
|
+
console.log(`Added rule ${r.id}: ${r.value}${r.tag ? ` [${r.tag}]` : ""}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log("No rules added.");
|
|
45
|
+
// Show errors if present
|
|
46
|
+
if (result.errors) {
|
|
47
|
+
for (const e of result.errors) {
|
|
48
|
+
console.error(` Error: ${JSON.stringify(e)}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
// --- stream rules ---
|
|
59
|
+
stream
|
|
60
|
+
.command("rules")
|
|
61
|
+
.description("List current filtered stream rules")
|
|
62
|
+
.option("--account <name>", "Account to use")
|
|
63
|
+
.option("--json", "Output raw JSON")
|
|
64
|
+
.action(async (opts) => {
|
|
65
|
+
try {
|
|
66
|
+
const client = await getClient(opts.account);
|
|
67
|
+
const result = await client.stream.getRules();
|
|
68
|
+
if (opts.json) {
|
|
69
|
+
outputJson(result);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const rules = result.data ?? [];
|
|
73
|
+
if (rules.length === 0) {
|
|
74
|
+
console.log("No rules configured.");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
for (const r of rules) {
|
|
78
|
+
const tag = r.tag ? ` [${r.tag}]` : "";
|
|
79
|
+
console.log(` ${r.id} ${r.value}${tag}`);
|
|
80
|
+
}
|
|
81
|
+
console.log(`\n${rules.length} rule${rules.length !== 1 ? "s" : ""}`);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// --- stream remove <rule-id> ---
|
|
89
|
+
stream
|
|
90
|
+
.command("remove <ruleId>")
|
|
91
|
+
.description("Remove a filtered stream rule by ID")
|
|
92
|
+
.option("--account <name>", "Account to use")
|
|
93
|
+
.option("--json", "Output raw JSON")
|
|
94
|
+
.action(async (ruleId, opts) => {
|
|
95
|
+
try {
|
|
96
|
+
const client = await getClient(opts.account);
|
|
97
|
+
const result = await client.stream.updateRules({
|
|
98
|
+
delete: { ids: [ruleId] },
|
|
99
|
+
});
|
|
100
|
+
if (opts.json) {
|
|
101
|
+
outputJson(result);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const summary = result.meta?.summary;
|
|
105
|
+
const deleted = summary?.deleted ?? 0;
|
|
106
|
+
if (deleted > 0) {
|
|
107
|
+
console.log(`Removed rule ${ruleId}`);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
console.log(`Rule ${ruleId} not found or already removed.`);
|
|
111
|
+
if (result.errors) {
|
|
112
|
+
for (const e of result.errors) {
|
|
113
|
+
console.error(` Error: ${JSON.stringify(e)}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// --- stream clear ---
|
|
124
|
+
stream
|
|
125
|
+
.command("clear")
|
|
126
|
+
.description("Remove all filtered stream rules")
|
|
127
|
+
.option("--account <name>", "Account to use")
|
|
128
|
+
.option("--json", "Output raw JSON")
|
|
129
|
+
.action(async (opts) => {
|
|
130
|
+
try {
|
|
131
|
+
const client = await getClient(opts.account);
|
|
132
|
+
// First get all current rule IDs
|
|
133
|
+
const current = await client.stream.getRules();
|
|
134
|
+
const rules = current.data ?? [];
|
|
135
|
+
if (rules.length === 0) {
|
|
136
|
+
console.log("No rules to remove.");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const ids = rules
|
|
140
|
+
.map((r) => r.id)
|
|
141
|
+
.filter((id) => !!id);
|
|
142
|
+
const result = await client.stream.updateRules({
|
|
143
|
+
delete: { ids },
|
|
144
|
+
});
|
|
145
|
+
if (opts.json) {
|
|
146
|
+
outputJson(result);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const summary = result.meta?.summary;
|
|
150
|
+
const deleted = summary?.deleted ?? ids.length;
|
|
151
|
+
console.log(`Cleared ${deleted} rule${deleted !== 1 ? "s" : ""}.`);
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
// --- stream connect ---
|
|
159
|
+
stream
|
|
160
|
+
.command("connect")
|
|
161
|
+
.description("Connect to filtered stream and output posts as they arrive")
|
|
162
|
+
.option("--json", "Output raw JSON lines")
|
|
163
|
+
.option("--quiet", "Output only post IDs")
|
|
164
|
+
.option("--account <name>", "Account to use")
|
|
165
|
+
.action(async (opts) => {
|
|
166
|
+
try {
|
|
167
|
+
const client = await getClient(opts.account);
|
|
168
|
+
// Connect to the filtered stream with tweet fields for human-readable output
|
|
169
|
+
const streamOpts = {};
|
|
170
|
+
if (!opts.quiet) {
|
|
171
|
+
streamOpts.tweetFields = ["created_at", "author_id", "text"];
|
|
172
|
+
streamOpts.expansions = ["author_id"];
|
|
173
|
+
streamOpts.userFields = ["name", "username"];
|
|
174
|
+
}
|
|
175
|
+
console.error("Connecting to filtered stream...");
|
|
176
|
+
const eventStream = await client.stream.posts(streamOpts);
|
|
177
|
+
// Handle graceful shutdown on Ctrl+C
|
|
178
|
+
const cleanup = () => {
|
|
179
|
+
console.error("\nDisconnecting...");
|
|
180
|
+
eventStream.close();
|
|
181
|
+
process.exit(0);
|
|
182
|
+
};
|
|
183
|
+
process.on("SIGINT", cleanup);
|
|
184
|
+
process.on("SIGTERM", cleanup);
|
|
185
|
+
console.error("Connected. Waiting for posts... (Ctrl+C to stop)\n");
|
|
186
|
+
// Listen for data events using the async iterator
|
|
187
|
+
for await (const event of eventStream) {
|
|
188
|
+
if (opts.json) {
|
|
189
|
+
// Raw JSON lines mode
|
|
190
|
+
console.log(JSON.stringify(event));
|
|
191
|
+
}
|
|
192
|
+
else if (opts.quiet) {
|
|
193
|
+
// Just post IDs
|
|
194
|
+
const id = event.data?.id;
|
|
195
|
+
if (id)
|
|
196
|
+
console.log(id);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
// Human-readable output
|
|
200
|
+
formatStreamEvent(event);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
console.error("Stream ended.");
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
/** Print a single streamed tweet event in human-readable format. */
|
|
212
|
+
function formatStreamEvent(event) {
|
|
213
|
+
const tweet = event.data;
|
|
214
|
+
if (!tweet)
|
|
215
|
+
return;
|
|
216
|
+
const lines = [];
|
|
217
|
+
// Try to find author from includes
|
|
218
|
+
const authorId = tweet.author_id;
|
|
219
|
+
const users = event.includes?.users ?? [];
|
|
220
|
+
const author = authorId
|
|
221
|
+
? users.find((u) => u.id === authorId)
|
|
222
|
+
: undefined;
|
|
223
|
+
if (author) {
|
|
224
|
+
lines.push(`@${author.username} (${author.name})`);
|
|
225
|
+
}
|
|
226
|
+
// Tweet text
|
|
227
|
+
const text = tweet.text ?? "";
|
|
228
|
+
lines.push(` ${text.replace(/\n/g, "\n ")}`);
|
|
229
|
+
// Matched rules
|
|
230
|
+
const rules = event.matching_rules ?? [];
|
|
231
|
+
if (rules.length > 0) {
|
|
232
|
+
const ruleLabels = rules
|
|
233
|
+
.map((r) => r.tag ?? r.id ?? "unknown")
|
|
234
|
+
.join(", ");
|
|
235
|
+
lines.push(` rules: ${ruleLabels}`);
|
|
236
|
+
}
|
|
237
|
+
// ID and timestamp
|
|
238
|
+
const meta = [];
|
|
239
|
+
if (tweet.created_at) {
|
|
240
|
+
meta.push(new Date(tweet.created_at).toLocaleString());
|
|
241
|
+
}
|
|
242
|
+
if (tweet.id) {
|
|
243
|
+
meta.push(`id:${tweet.id}`);
|
|
244
|
+
}
|
|
245
|
+
if (meta.length > 0) {
|
|
246
|
+
lines.push(` ${meta.join(" ยท ")}`);
|
|
247
|
+
}
|
|
248
|
+
console.log(lines.join("\n"));
|
|
249
|
+
console.log(); // blank line between tweets
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/commands/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,gEAAgE;AAChE,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,MAAM,GAAG,OAAO;SACnB,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,0CAA0C,CAAC,CAAC;IAE3D,6BAA6B;IAC7B,MAAM;SACH,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,cAAc,EAAE,qBAAqB,CAAC;SAC7C,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAAI,EAAE,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,mCAAmC;YACnC,MAAM,IAAI,GAAoC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;YAC/D,IAAI,IAAI,CAAC,GAAG;gBAAE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;YAElC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAEhE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;oBACtB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7E,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;gBAC/B,yBAAyB;gBACzB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;wBAC9B,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBACjD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,uBAAuB;IACvB,MAAM;SACH,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,oCAAoC,CAAC;SACjD,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YAE9C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;gBACpC,OAAO;YACT,CAAC;YAED,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;gBACtB,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,MAAM,QAAQ,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,kCAAkC;IAClC,MAAM;SACH,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,qCAAqC,CAAC;SAClD,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAAI,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;gBAC7C,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE;aAC1B,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,OAEhB,CAAC;YACd,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,CAAC,CAAC;YAEtC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,EAAE,CAAC,CAAC;YACxC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,QAAQ,MAAM,gCAAgC,CAAC,CAAC;gBAC5D,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;oBAClB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;wBAC9B,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBACjD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,uBAAuB;IACvB,MAAM;SACH,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,iCAAiC;YACjC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YAEjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;gBACnC,OAAO;YACT,CAAC;YAED,MAAM,GAAG,GAAG,KAAK;iBACd,GAAG,CAAC,CAAC,CAAkB,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBACjC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAEtC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC;gBAC7C,MAAM,EAAE,EAAE,GAAG,EAAE;aAChB,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,OAEhB,CAAC;YACd,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,WAAW,OAAO,QAAQ,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACrE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,yBAAyB;IACzB,MAAM;SACH,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,4DAA4D,CAAC;SACzE,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SACzC,MAAM,CAAC,SAAS,EAAE,sBAAsB,CAAC;SACzC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,6EAA6E;YAC7E,MAAM,UAAU,GAA4B,EAAE,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAChB,UAAU,CAAC,WAAW,GAAG,CAAC,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;gBAC7D,UAAU,CAAC,UAAU,GAAG,CAAC,WAAW,CAAC,CAAC;gBACtC,UAAU,CAAC,UAAU,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAC/C,CAAC;YAED,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;YAClD,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAE1D,qCAAqC;YACrC,MAAM,OAAO,GAAG,GAAG,EAAE;gBACnB,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;gBACpC,WAAW,CAAC,KAAK,EAAE,CAAC;gBACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC,CAAC;YACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAE/B,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;YAEpE,kDAAkD;YAClD,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;gBACtC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;oBACd,sBAAsB;oBACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;gBACrC,CAAC;qBAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBACtB,gBAAgB;oBAChB,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;oBAC1B,IAAI,EAAE;wBAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC1B,CAAC;qBAAM,CAAC;oBACN,wBAAwB;oBACxB,iBAAiB,CAAC,KAAK,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;YAED,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,oEAAoE;AACpE,SAAS,iBAAiB,CAAC,KAI1B;IACC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;IACzB,IAAI,CAAC,KAAK;QAAE,OAAO;IAEnB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,mCAAmC;IACnC,MAAM,QAAQ,GAAG,KAAK,CAAC,SAA+B,CAAC;IACvD,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAG,QAAQ;QACrB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC;QACtC,CAAC,CAAC,SAAS,CAAC;IAEd,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;IACrD,CAAC;IAED,aAAa;IACb,MAAM,IAAI,GAAI,KAAK,CAAC,IAAe,IAAI,EAAE,CAAC;IAC1C,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAE/C,gBAAgB;IAChB,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,IAAI,EAAE,CAAC;IACzC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,UAAU,GAAG,KAAK;aACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,IAAI,SAAS,CAAC;aACtC,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,YAAY,UAAU,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,mBAAmB;IACnB,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,UAAoB,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;QACb,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,4BAA4B;AAC7C,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getClient } from "../lib/api.js";
|
|
2
|
+
import { outputJson } from "../lib/cost.js";
|
|
3
|
+
import { buildUserMap, formatTweetList } from "../lib/format.js";
|
|
4
|
+
import { resolveAuthenticatedUserId, resolveUserId } from "../lib/resolve.js";
|
|
5
|
+
const TWEET_FIELDS = ["created_at", "public_metrics", "author_id"];
|
|
6
|
+
const EXPANSIONS = ["author_id"];
|
|
7
|
+
const USER_FIELDS = ["name", "username"];
|
|
8
|
+
export function registerTimelineCommand(program) {
|
|
9
|
+
program
|
|
10
|
+
.command("timeline [username]")
|
|
11
|
+
.description("View home timeline, or a user's posts with @username argument")
|
|
12
|
+
.option("-n, --limit <n>", "Max results (1-100)", "20")
|
|
13
|
+
.option("--json", "Output raw JSON")
|
|
14
|
+
.option("--account <name>", "Account to use")
|
|
15
|
+
.action(async (username, opts) => {
|
|
16
|
+
try {
|
|
17
|
+
const client = await getClient(opts.account);
|
|
18
|
+
const fieldOpts = {
|
|
19
|
+
tweetFields: TWEET_FIELDS,
|
|
20
|
+
expansions: EXPANSIONS,
|
|
21
|
+
userFields: USER_FIELDS,
|
|
22
|
+
maxResults: parseInt(opts.limit, 10),
|
|
23
|
+
};
|
|
24
|
+
let result;
|
|
25
|
+
if (username) {
|
|
26
|
+
// User timeline: fetch their posts
|
|
27
|
+
const userId = await resolveUserId(username, opts.account);
|
|
28
|
+
result = await client.users.getPosts(userId, fieldOpts);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
// Home timeline: reverse-chronological feed
|
|
32
|
+
const myId = await resolveAuthenticatedUserId(opts.account);
|
|
33
|
+
result = await client.users.getTimeline(myId, fieldOpts);
|
|
34
|
+
}
|
|
35
|
+
if (opts.json) {
|
|
36
|
+
outputJson(result);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const tweets = result.data ?? [];
|
|
40
|
+
if (tweets.length === 0) {
|
|
41
|
+
console.log("No posts found.");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const usersById = buildUserMap(result.includes?.users);
|
|
45
|
+
// Header
|
|
46
|
+
if (username) {
|
|
47
|
+
const clean = username.replace(/^@/, "");
|
|
48
|
+
console.log(`Posts from @${clean}:\n`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.log("Home timeline:\n");
|
|
52
|
+
}
|
|
53
|
+
console.log(formatTweetList(tweets, usersById));
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/commands/timeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trends commands: view trending topics.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* xc trends โ personalized trends
|
|
6
|
+
* xc trends <woeid> โ trends by location (WOEID)
|
|
7
|
+
* xc trends --global โ worldwide trends (WOEID 1)
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from "commander";
|
|
10
|
+
export declare function registerTrendsCommand(program: Command): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trends commands: view trending topics.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* xc trends โ personalized trends
|
|
6
|
+
* xc trends <woeid> โ trends by location (WOEID)
|
|
7
|
+
* xc trends --global โ worldwide trends (WOEID 1)
|
|
8
|
+
*/
|
|
9
|
+
import { getClient } from "../lib/api.js";
|
|
10
|
+
import { outputJson } from "../lib/cost.js";
|
|
11
|
+
export function registerTrendsCommand(program) {
|
|
12
|
+
program
|
|
13
|
+
.command("trends [woeid]")
|
|
14
|
+
.description("View trending topics (personalized, by WOEID, or --global)")
|
|
15
|
+
.option("--global", "Show worldwide trends (WOEID 1)")
|
|
16
|
+
.option("--json", "Output raw JSON")
|
|
17
|
+
.option("--account <name>", "Account to use")
|
|
18
|
+
.action(async (woeid, opts) => {
|
|
19
|
+
try {
|
|
20
|
+
const client = await getClient(opts.account);
|
|
21
|
+
let result;
|
|
22
|
+
const locationId = opts.global ? 1 : woeid ? parseInt(woeid, 10) : undefined;
|
|
23
|
+
if (locationId !== undefined) {
|
|
24
|
+
result = await client.trends.getByWoeid(locationId);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
result = await client.trends.getPersonalized();
|
|
28
|
+
}
|
|
29
|
+
if (opts.json) {
|
|
30
|
+
outputJson(result);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const trends = (result.data ?? []);
|
|
34
|
+
if (trends.length === 0) {
|
|
35
|
+
console.log("No trends found.");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const label = locationId !== undefined
|
|
39
|
+
? locationId === 1
|
|
40
|
+
? "Worldwide"
|
|
41
|
+
: `WOEID ${locationId}`
|
|
42
|
+
: "Personalized";
|
|
43
|
+
console.log(`${label} trends:\n`);
|
|
44
|
+
for (let i = 0; i < trends.length; i++) {
|
|
45
|
+
const trend = trends[i];
|
|
46
|
+
const name = trend.trendName ?? trend.name ?? "Unknown";
|
|
47
|
+
const countStr = trend.tweetCount
|
|
48
|
+
? ` (${trend.tweetCount.toLocaleString()} posts)`
|
|
49
|
+
: "";
|
|
50
|
+
console.log(` ${i + 1}. ${name}${countStr}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=trends.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trends.js","sourceRoot":"","sources":["../../src/commands/trends.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAU5C,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,4DAA4D,CAAC;SACzE,MAAM,CAAC,UAAU,EAAE,iCAAiC,CAAC;SACrD,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,KAAyB,EAAE,IAAI,EAAE,EAAE;QAChD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,IAAI,MAAM,CAAC;YACX,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAE7E,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC7B,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;YACtD,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YACjD,CAAC;YAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAY,CAAC;YAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;gBAChC,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,UAAU,KAAK,SAAS;gBACpC,CAAC,CAAC,UAAU,KAAK,CAAC;oBAChB,CAAC,CAAC,WAAW;oBACb,CAAC,CAAC,SAAS,UAAU,EAAE;gBACzB,CAAC,CAAC,cAAc,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,YAAY,CAAC,CAAC;YAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACvC,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;gBACxB,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC;gBACxD,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU;oBAC/B,CAAC,CAAC,KAAK,KAAK,CAAC,UAAU,CAAC,cAAc,EAAE,SAAS;oBACjD,CAAC,CAAC,EAAE,CAAC;gBACP,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,QAAQ,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getClient } from "../lib/api.js";
|
|
2
|
+
import { outputJson } from "../lib/cost.js";
|
|
3
|
+
export function registerUsageCommand(program) {
|
|
4
|
+
program
|
|
5
|
+
.command("usage")
|
|
6
|
+
.description("Show API usage stats")
|
|
7
|
+
.option("--json", "Output raw JSON")
|
|
8
|
+
.option("--account <name>", "Account to use")
|
|
9
|
+
.action(async (opts) => {
|
|
10
|
+
try {
|
|
11
|
+
const client = await getClient(opts.account);
|
|
12
|
+
const result = await client.usage.get();
|
|
13
|
+
if (opts.json) {
|
|
14
|
+
outputJson(result);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const data = result.data;
|
|
18
|
+
if (!data) {
|
|
19
|
+
console.log("No usage data available.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Show cap reset day if present
|
|
23
|
+
if (data.capResetDay) {
|
|
24
|
+
console.log(`Cap resets on day ${data.capResetDay} of each month\n`);
|
|
25
|
+
}
|
|
26
|
+
// Summarize recent daily usage
|
|
27
|
+
const days = (data.dailyProjectUsage ?? []);
|
|
28
|
+
if (days.length === 0) {
|
|
29
|
+
console.log("No daily usage data available.");
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
console.log("Daily tweet usage:\n");
|
|
33
|
+
for (const day of days) {
|
|
34
|
+
const date = new Date(day.date).toLocaleDateString();
|
|
35
|
+
const total = day.usage.reduce((sum, u) => sum + u.tweets, 0);
|
|
36
|
+
console.log(` ${date}: ${total.toLocaleString()} tweets`);
|
|
37
|
+
// Per-app breakdown if multiple apps
|
|
38
|
+
if (day.usage.length > 1) {
|
|
39
|
+
for (const u of day.usage) {
|
|
40
|
+
const appName = u.app?.appName ?? "unknown";
|
|
41
|
+
console.log(` ${appName}: ${u.tweets.toLocaleString()}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/commands/usage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAU5C,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,sBAAsB,CAAC;SACnC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;YAExC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAA2C,CAAC;YAChE,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;gBACxC,OAAO;YACT,CAAC;YAED,gCAAgC;YAChC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACrB,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,WAAW,kBAAkB,CAAC,CAAC;YACvE,CAAC;YAED,+BAA+B;YAC/B,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,iBAAiB,IAAI,EAAE,CAAsB,CAAC;YACjE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACpC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC;gBACrD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;gBAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,KAAK,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;gBAE3D,qCAAqC;gBACrC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACzB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;wBAC1B,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,IAAI,SAAS,CAAC;wBAC5C,OAAO,CAAC,GAAG,CAAC,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;oBAC9D,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { getClient } from "../lib/api.js";
|
|
2
|
+
import { outputJson } from "../lib/cost.js";
|
|
3
|
+
const USER_FIELDS = ["created_at", "description", "public_metrics"];
|
|
4
|
+
export function registerUserCommand(program) {
|
|
5
|
+
program
|
|
6
|
+
.command("user <username>")
|
|
7
|
+
.description("Look up a user by @username")
|
|
8
|
+
.option("--json", "Output raw JSON")
|
|
9
|
+
.option("--account <name>", "Account to use")
|
|
10
|
+
.action(async (username, opts) => {
|
|
11
|
+
try {
|
|
12
|
+
const clean = username.replace(/^@/, "");
|
|
13
|
+
const client = await getClient(opts.account);
|
|
14
|
+
const result = await client.users.getByUsername(clean, {
|
|
15
|
+
userFields: USER_FIELDS,
|
|
16
|
+
});
|
|
17
|
+
if (opts.json) {
|
|
18
|
+
outputJson(result);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const data = result.data;
|
|
22
|
+
if (!data) {
|
|
23
|
+
console.error(`User @${clean} not found.`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const m = data.publicMetrics;
|
|
27
|
+
console.log(`@${data.username} (${data.name})`);
|
|
28
|
+
if (data.description)
|
|
29
|
+
console.log(` ${data.description}`);
|
|
30
|
+
if (m) {
|
|
31
|
+
console.log(` ${(m.followersCount ?? 0).toLocaleString()} followers ยท ${(m.followingCount ?? 0).toLocaleString()} following ยท ${(m.tweetCount ?? 0).toLocaleString()} posts`);
|
|
32
|
+
}
|
|
33
|
+
if (data.createdAt) {
|
|
34
|
+
console.log(` Joined ${new Date(data.createdAt).toLocaleDateString()}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=user.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user.js","sourceRoot":"","sources":["../../src/commands/user.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,WAAW,GAAG,CAAC,YAAY,EAAE,aAAa,EAAE,gBAAgB,CAAC,CAAC;AAEpE,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAI,EAAE,EAAE;QACvC,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACzC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,EAAE;gBACrD,UAAU,EAAE,WAAW;aACxB,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACzB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,SAAS,KAAK,aAAa,CAAC,CAAC;gBAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,CAAC,GAAG,IAAI,CAAC,aAAmD,CAAC;YAEnE,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;YAChD,IAAI,IAAI,CAAC,WAAW;gBAAE,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YAC3D,IAAI,CAAC,EAAE,CAAC;gBACN,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE,QAAQ,CAClK,CAAC;YACJ,CAAC;YACD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,OAAO,CAAC,GAAG,CACT,YAAY,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,EAAE,CAC5D,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User search command.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* xc usersearch <query> โ search for users by keyword
|
|
6
|
+
*/
|
|
7
|
+
import { getClient } from "../lib/api.js";
|
|
8
|
+
import { outputJson } from "../lib/cost.js";
|
|
9
|
+
import { formatUserLine } from "../lib/format.js";
|
|
10
|
+
export function registerUserSearchCommand(program) {
|
|
11
|
+
program
|
|
12
|
+
.command("usersearch <query>")
|
|
13
|
+
.description("Search for users by keyword")
|
|
14
|
+
.option("-n, --limit <n>", "Max results (1-100)", "20")
|
|
15
|
+
.option("--json", "Output raw JSON")
|
|
16
|
+
.option("--account <name>", "Account to use")
|
|
17
|
+
.action(async (query, opts) => {
|
|
18
|
+
try {
|
|
19
|
+
const client = await getClient(opts.account);
|
|
20
|
+
const result = await client.users.search(query, {
|
|
21
|
+
userFields: ["username", "name", "public_metrics", "description"],
|
|
22
|
+
maxResults: parseInt(opts.limit, 10),
|
|
23
|
+
});
|
|
24
|
+
if (opts.json) {
|
|
25
|
+
outputJson(result);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const users = (result.data ?? []);
|
|
29
|
+
if (users.length === 0) {
|
|
30
|
+
console.log(`No users found for "${query}".`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
console.log(`Users matching "${query}":\n`);
|
|
34
|
+
for (const user of users) {
|
|
35
|
+
console.log(formatUserLine(user));
|
|
36
|
+
if (user.description) {
|
|
37
|
+
console.log(` ${user.description.replace(/\n/g, " ").slice(0, 100)}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
console.log(`\nโ ${users.length} shown`);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=usersearch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usersearch.js","sourceRoot":"","sources":["../../src/commands/usersearch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAmB,MAAM,kBAAkB,CAAC;AAEnE,MAAM,UAAU,yBAAyB,CAAC,OAAgB;IACxD,OAAO;SACJ,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,iBAAiB,EAAE,qBAAqB,EAAE,IAAI,CAAC;SACtD,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC;SACnC,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,CAAC;SAC5C,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,IAAI,EAAE,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAE7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE;gBAC9C,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,aAAa,CAAC;gBACjE,UAAU,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;aACrC,CAAC,CAAC;YAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,UAAU,CAAC,MAAM,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAiB,CAAC;YAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,uBAAuB,KAAK,IAAI,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,MAAM,CAAC,CAAC;YAC5C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;gBAClC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;oBACrB,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC3E,CAAC;YACH,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;YACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getClient } from "../lib/api.js";
|
|
2
|
+
import { outputJson } from "../lib/cost.js";
|
|
3
|
+
const USER_FIELDS = [
|
|
4
|
+
"created_at",
|
|
5
|
+
"description",
|
|
6
|
+
"public_metrics",
|
|
7
|
+
"verified",
|
|
8
|
+
"location",
|
|
9
|
+
"url",
|
|
10
|
+
"profile_image_url",
|
|
11
|
+
];
|
|
12
|
+
export function registerWhoamiCommand(program) {
|
|
13
|
+
program
|
|
14
|
+
.command("whoami")
|
|
15
|
+
.description("Show the authenticated user")
|
|
16
|
+
.option("--account <name>", "Account to check")
|
|
17
|
+
.option("--json", "Output raw JSON")
|
|
18
|
+
.action(async (opts) => {
|
|
19
|
+
try {
|
|
20
|
+
const client = await getClient(opts.account);
|
|
21
|
+
const result = await client.users.getMe({ userFields: USER_FIELDS });
|
|
22
|
+
if (opts.json) {
|
|
23
|
+
outputJson(result);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const data = result.data;
|
|
27
|
+
if (!data) {
|
|
28
|
+
console.error("Could not fetch user info.");
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const m = data.publicMetrics;
|
|
32
|
+
console.log(`@${data.username} (${data.name})`);
|
|
33
|
+
if (data.description)
|
|
34
|
+
console.log(` ${data.description}`);
|
|
35
|
+
if (data.location)
|
|
36
|
+
console.log(` ๐ ${data.location}`);
|
|
37
|
+
if (data.url)
|
|
38
|
+
console.log(` ๐ ${data.url}`);
|
|
39
|
+
if (data.verified)
|
|
40
|
+
console.log(` โ Verified`);
|
|
41
|
+
if (m) {
|
|
42
|
+
console.log(` ${(m.followersCount ?? 0).toLocaleString()} followers ยท ${(m.followingCount ?? 0).toLocaleString()} following ยท ${(m.tweetCount ?? 0).toLocaleString()} posts`);
|
|
43
|
+
}
|
|
44
|
+
if (data.createdAt) {
|
|
45
|
+
console.log(` Joined ${new Date(data.createdAt).toLocaleDateString()}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=whoami.js.map
|