@cm-growth-hacking/twitter-client 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Thaddeus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,360 @@
1
+ # @thaddeus/twitter-client
2
+
3
+ Lightweight Twitter/X GraphQL client and CLI tool.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Install
9
+ bun install
10
+
11
+ # Set credentials (get from browser DevTools → Application → Cookies)
12
+ export TWITTER_AUTH_TOKEN="your_auth_token"
13
+ export TWITTER_CT0="your_ct0_token"
14
+
15
+ # Search tweets
16
+ bun run src/cli.ts search "bitcoin"
17
+
18
+ # Post tweet
19
+ bun run src/cli.ts tweet "Hello World!"
20
+ ```
21
+
22
+ ## Features
23
+
24
+ - 🚀 Zero dependencies (except for CLI colors)
25
+ - 📝 Full TypeScript support
26
+ - 🔐 Cookie-based authentication
27
+ - 🎯 GraphQL API integration
28
+ - 💻 CLI tool included
29
+ - ⚡ Bun-optimized
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install @thaddeus/twitter-client
35
+ ```
36
+
37
+ Both `npm` and `bun` work for installation.
38
+
39
+ Or globally for the CLI:
40
+
41
+ ```bash
42
+ npm install -g @thaddeus/twitter-client
43
+ ```
44
+
45
+ ## Authentication
46
+
47
+ This client uses Twitter's cookie-based authentication (same as the web app). You'll need two values from your browser:
48
+
49
+ 1. **auth_token** - From cookie `auth_token`
50
+ 2. **ct0** - From cookie `ct0`
51
+
52
+ ### Getting Credentials
53
+
54
+ 1. Open Twitter/X in your browser
55
+ 2. Open Developer Tools (F12)
56
+ 3. Go to Application > Storage > Cookies
57
+ 4. Copy the values for `auth_token` and `ct0`
58
+
59
+ ### Setting Up Environment
60
+
61
+ Create a `.env` file:
62
+
63
+ ```bash
64
+ TWITTER_AUTH_TOKEN=your_auth_token_here
65
+ TWITTER_CT0=your_ct0_here
66
+ ```
67
+
68
+ ## Known Limitations
69
+
70
+ - **Tweet Posting Error 226**: New or low-activity accounts may get "looks automated" error. Try posting from web interface first to warm up the account.
71
+ - **Rate Limiting**: Not yet implemented - Twitter may temporarily block rapid requests.
72
+ - **Query ID Rotation**: Query IDs rotate frequently (daily/weekly). Use `twitter update-query-ids --fresh` if commands fail.
73
+
74
+ ## Query ID Management
75
+
76
+ Twitter rotates GraphQL query IDs frequently. This client handles this automatically:
77
+
78
+ **Auto-Refresh (Recommended):**
79
+ - On 404 errors, the client automatically refreshes query IDs and retries
80
+ - No manual intervention needed
81
+ - Cache updated to `~/.config/twitter-client/query-ids.json` (24h TTL)
82
+
83
+ **Manual Refresh:**
84
+ ```bash
85
+ twitter update-query-ids # Update if cache is stale
86
+ twitter update-query-ids --fresh # Force refresh regardless of cache age
87
+ ```
88
+
89
+ **How It Works:**
90
+ 1. Client fetches Twitter's web client JavaScript bundle
91
+ 2. Extracts current query IDs using regex patterns
92
+ 3. Caches IDs locally with 24-hour TTL
93
+ 4. Falls back to baked-in IDs if scraping fails
94
+
95
+ **Troubleshooting:**
96
+ - If commands fail with "persisted query not found": Run `twitter update-query-ids --fresh`
97
+ - Check cache freshness: `cat ~/.config/twitter-client/query-ids.json`
98
+ - Clear cache: `rm ~/.config/twitter-client/query-ids.json`
99
+
100
+ ## Commands
101
+
102
+ ### whoami
103
+
104
+ Shows your authenticated Twitter account information.
105
+
106
+ ```bash
107
+ twitter whoami
108
+ ```
109
+
110
+ Example output:
111
+ ```
112
+ Logged in as: @username (Display Name)
113
+ User ID: 1234567890
114
+ Followers: 1,234
115
+ Following: 567
116
+ ```
117
+
118
+ **Note:** The `whoami` command uses Twitter's GraphQL API. If you encounter authentication errors, verify your environment variables are set correctly:
119
+ ```bash
120
+ echo $TWITTER_AUTH_TOKEN
121
+ echo $TWITTER_CT0
122
+ ```
123
+
124
+ ## CLI Usage
125
+
126
+ Once installed globally, the `twitter` command is available:
127
+
128
+ ```bash
129
+ # Show current user info
130
+ twitter whoami
131
+
132
+ # Search for tweets
133
+ twitter search "typescript"
134
+
135
+ # Post a tweet
136
+ twitter tweet "Hello, world!"
137
+
138
+ # Get a tweet by ID or URL
139
+ twitter get 1234567890
140
+ twitter get https://x.com/user/status/1234567890
141
+
142
+ # Get tweets from a user
143
+ twitter user username
144
+
145
+ # Get news timeline
146
+ twitter news
147
+
148
+ # Get mentions
149
+ twitter mentions
150
+ ```
151
+
152
+ ## Library Usage
153
+
154
+ ```typescript
155
+ import { TwitterClient } from '@thaddeus/twitter-client';
156
+
157
+ const client = new TwitterClient({
158
+ authToken: process.env.TWITTER_AUTH_TOKEN!,
159
+ ct0: process.env.TWITTER_CT0!,
160
+ });
161
+
162
+ // Get current user info
163
+ const result = await client.whoami();
164
+ if (result.success) {
165
+ console.log(`@${result.user.username}`);
166
+ }
167
+
168
+ // Search for tweets
169
+ const searchResult = await client.search('typescript');
170
+ if (searchResult.success) {
171
+ searchResult.tweets.forEach(tweet => {
172
+ console.log(`@${tweet.author.username}: ${tweet.text}`);
173
+ });
174
+ }
175
+
176
+ // Post a tweet
177
+ const postResult = await client.tweet('Hello from the API!');
178
+ if (postResult.success) {
179
+ console.log(`Tweet ID: ${postResult.tweetId}`);
180
+ }
181
+
182
+ // Get a tweet
183
+ const tweetResult = await client.getTweet('1234567890');
184
+ if (tweetResult.success) {
185
+ console.log(tweetResult.tweet.text);
186
+ }
187
+
188
+ // Get user's tweets
189
+ const userResult = await client.getUserTweets('username');
190
+ if (userResult.success) {
191
+ userResult.tweets.forEach(tweet => {
192
+ console.log(tweet.text);
193
+ });
194
+ }
195
+
196
+ // Reply to a tweet
197
+ const replyResult = await client.reply('1234567890', 'This is a reply');
198
+
199
+ // Like a tweet
200
+ const likeResult = await client.likeTweet('1234567890');
201
+
202
+ // Unlike a tweet
203
+ const unlikeResult = await client.unlikeTweet('1234567890');
204
+
205
+ // Get news timeline
206
+ const newsResult = await client.getNews();
207
+ if (newsResult.success) {
208
+ newsResult.items.forEach(item => {
209
+ console.log(item.headline);
210
+ });
211
+ }
212
+
213
+ // Get mentions
214
+ const mentionsResult = await client.getMentions();
215
+ if (mentionsResult.success) {
216
+ mentionsResult.tweets.forEach(tweet => {
217
+ console.log(`@${tweet.author.username}: ${tweet.text}`);
218
+ });
219
+ }
220
+ ```
221
+
222
+ ## API Reference
223
+
224
+ ### TwitterClient
225
+
226
+ #### Constructor
227
+
228
+ ```typescript
229
+ new TwitterClient(options: {
230
+ authToken: string;
231
+ ct0: string;
232
+ timeout?: number;
233
+ })
234
+ ```
235
+
236
+ #### Methods
237
+
238
+ ##### `whoami(): Promise<UserResult>`
239
+ Verify authentication and get current user info.
240
+
241
+ ##### `search(query: string, count?: number): Promise<SearchResult>`
242
+ Search for tweets. Count must be between 1-200 (default: 20).
243
+
244
+ ##### `tweet(text: string): Promise<PostResult>`
245
+ Post a new tweet.
246
+
247
+ ##### `getTweet(tweetIdOrUrl: string): Promise<TweetResult>`
248
+ Get a single tweet by ID or URL.
249
+
250
+ ##### `getUserTweets(username: string, count?: number): Promise<TweetsResult>`
251
+ Get recent tweets from a user.
252
+
253
+ ##### `reply(tweetId: string, text: string): Promise<PostResult>`
254
+ Reply to a tweet.
255
+
256
+ ##### `likeTweet(tweetId: string): Promise<PostResult>`
257
+ Like a tweet.
258
+
259
+ ##### `unlikeTweet(tweetId: string): Promise<PostResult>`
260
+ Unlike a tweet.
261
+
262
+ ##### `getNews(count?: number): Promise<NewsResult>`
263
+ Get news timeline (For You timeline). Count must be between 1-200 (default: 20).
264
+
265
+ ##### `getMentions(count?: number): Promise<TweetsResult>`
266
+ Get mentions timeline. Count must be between 1-200 (default: 20).
267
+
268
+ ### Types
269
+
270
+ #### `Tweet`
271
+ ```typescript
272
+ interface Tweet {
273
+ id: string;
274
+ text: string;
275
+ author: User;
276
+ createdAt: string;
277
+ likeCount: number;
278
+ retweetCount: number;
279
+ replyCount: number;
280
+ quoteCount: number;
281
+ viewCount: number;
282
+ bookmarkCount: number;
283
+ media?: MediaItem[];
284
+ isQuote?: boolean;
285
+ quotedTweet?: Tweet;
286
+ isRetweet?: boolean;
287
+ retweetedTweet?: Tweet;
288
+ inReplyTo?: string;
289
+ conversationId?: string;
290
+ }
291
+ ```
292
+
293
+ #### `User`
294
+ ```typescript
295
+ interface User {
296
+ id: string;
297
+ username: string;
298
+ name: string;
299
+ description?: string;
300
+ followersCount?: number;
301
+ followingCount?: number;
302
+ isBlueVerified?: boolean;
303
+ profileImageUrl?: string;
304
+ createdAt?: string;
305
+ }
306
+ ```
307
+
308
+ #### `Result<T>`
309
+ All methods return a Result object:
310
+ ```typescript
311
+ interface Result<T> {
312
+ success: true;
313
+ data: T;
314
+ } | {
315
+ success: false;
316
+ error: string;
317
+ code: ErrorCode;
318
+ }
319
+ ```
320
+
321
+ ## Error Codes
322
+
323
+ - `AUTH_FAILED` - Authentication credentials are invalid or expired
324
+ - `NETWORK_ERROR` - Network request failed
325
+ - `RATE_LIMITED` - Rate limit exceeded
326
+ - `INVALID_INPUT` - Invalid input parameters
327
+ - `NOT_FOUND` - Resource not found
328
+ - `SERVER_ERROR` - Twitter server error
329
+ - `UNKNOWN_ERROR` - Unknown error occurred
330
+
331
+ ## Development
332
+
333
+ ```bash
334
+ # Install dependencies
335
+ bun install
336
+
337
+ # Run tests
338
+ bun test
339
+
340
+ # Run tests with live API calls
341
+ TWITTER_LIVE=1 bun test tests/live/
342
+
343
+ # Build
344
+ bun run build
345
+
346
+ # Run CLI directly
347
+ bun run dev
348
+ ```
349
+
350
+ ## License
351
+
352
+ MIT
353
+
354
+ ## Contributing
355
+
356
+ Contributions are welcome! Please open an issue or submit a pull request.
357
+
358
+ ## Disclaimer
359
+
360
+ This project is not affiliated with Twitter/X. Use at your own risk and make sure to comply with Twitter's Terms of Service.