x-reader 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
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,206 @@
1
+ # x-reader
2
+
3
+ [![npm version](https://img.shields.io/npm/v/x-reader)](https://www.npmjs.com/package/x-reader)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue)](https://www.typescriptlang.org/)
7
+
8
+ **Read-only Twitter/X CLI** for searching tweets, reading timelines, bookmarks, and replies from the terminal. Inspired by [Bird CLI](https://github.com/steipete/bird).
9
+
10
+ > Uses your own X/Twitter cookies. One user, one account. No API keys required.
11
+
12
+ ## Features
13
+
14
+ - **Search** tweets by keyword or advanced query (`from:`, `to:`, `filter:`, etc.)
15
+ - **Read** a user's timeline
16
+ - **Read** a single tweet by ID or URL
17
+ - **Read** replies to any tweet
18
+ - **Read** your bookmarks (with `--all` for full export)
19
+ - **Look up** user profiles by handle
20
+ - **JSON output** for piping into other tools (`jq`, scripts, etc.)
21
+ - **Auto-discovers** X's rotating GraphQL query IDs (no manual updates needed)
22
+ - **Zero config** beyond two browser cookies
23
+
24
+ ## Why x-reader?
25
+
26
+ - No Twitter API keys or developer account needed
27
+ - Read-only by design (no accidental tweets, likes, or follows)
28
+ - Works with X's current GraphQL endpoints
29
+ - Lightweight: single dependency (Commander)
30
+ - Scriptable: JSON output for automation and data pipelines
31
+
32
+ ## Install
33
+
34
+ ### From npm (recommended)
35
+
36
+ ```bash
37
+ npm install -g x-reader
38
+ ```
39
+
40
+ ### From source
41
+
42
+ ```bash
43
+ git clone https://github.com/DjinnFoundry/x-reader.git
44
+ cd x-reader
45
+ npm install
46
+ npm run build
47
+ npm link
48
+ ```
49
+
50
+ ## Quick start
51
+
52
+ ```bash
53
+ # 1. Set up authentication (interactive)
54
+ x-reader setup
55
+
56
+ # 2. Search tweets
57
+ x-reader search "machine learning"
58
+
59
+ # 3. Read a user's timeline
60
+ x-reader user-tweets @naval -n 10
61
+
62
+ # 4. Export your bookmarks as JSON
63
+ x-reader bookmarks --all --format json > bookmarks.json
64
+ ```
65
+
66
+ ## Authentication
67
+
68
+ You need two cookies from x.com: `auth_token` and `ct0`.
69
+
70
+ ### Option 1: Interactive setup
71
+ ```bash
72
+ x-reader setup
73
+ ```
74
+
75
+ ### Option 2: Environment variables
76
+ ```bash
77
+ export AUTH_TOKEN="your_auth_token"
78
+ export CT0="your_ct0"
79
+ ```
80
+
81
+ ### Option 3: CLI flags
82
+ ```bash
83
+ x-reader search "query" --auth-token xxx --ct0 yyy
84
+ ```
85
+
86
+ ### Where to find your cookies
87
+ 1. Go to [x.com](https://x.com) and log in
88
+ 2. Open DevTools (F12) -> Application -> Cookies -> x.com
89
+ 3. Copy `auth_token` and `ct0` values
90
+
91
+ Config is saved to `~/.config/x-reader/config.json`.
92
+
93
+ ## Usage
94
+
95
+ ### Search tweets
96
+ ```bash
97
+ x-reader search "machine learning"
98
+ x-reader search "from:elonmusk" -n 5
99
+ x-reader search "AI safety" --format json
100
+ ```
101
+
102
+ ### Read a user's timeline
103
+ ```bash
104
+ x-reader user-tweets @steipete
105
+ x-reader user-tweets elonmusk -n 10
106
+ x-reader user-tweets @naval --format json
107
+ ```
108
+
109
+ ### Read a single tweet
110
+ ```bash
111
+ x-reader read 1234567890
112
+ x-reader read https://x.com/user/status/1234567890
113
+ x-reader read https://x.com/user/status/1234567890 --format json
114
+ ```
115
+
116
+ ### Read replies
117
+ ```bash
118
+ x-reader replies 1234567890
119
+ x-reader replies https://x.com/user/status/1234567890 --format json
120
+ ```
121
+
122
+ ### Export bookmarks
123
+ ```bash
124
+ x-reader bookmarks
125
+ x-reader bookmarks -n 50
126
+ x-reader bookmarks --all --format json
127
+ ```
128
+
129
+ ### User lookup
130
+ ```bash
131
+ x-reader user-lookup @steipete
132
+ x-reader user-lookup naval --format json
133
+ ```
134
+
135
+ ### Query ID management
136
+ ```bash
137
+ # Show cached query IDs
138
+ x-reader query-ids
139
+
140
+ # Force refresh from x.com (when IDs rotate)
141
+ x-reader query-ids --refresh
142
+ ```
143
+
144
+ ## Output formats
145
+
146
+ - **text** (default) - human-readable
147
+ - **json** - machine-readable, pipe to `jq` or save to file
148
+
149
+ ```bash
150
+ # Pipe to jq
151
+ x-reader search "typescript" --format json | jq '.tweets[].text'
152
+
153
+ # Save to file
154
+ x-reader bookmarks --all --format json > my-bookmarks.json
155
+ ```
156
+
157
+ ## Programmatic use
158
+
159
+ ```typescript
160
+ import { XReaderClient } from 'x-reader';
161
+
162
+ const client = new XReaderClient({
163
+ cookies: { authToken: '...', ct0: '...' },
164
+ });
165
+
166
+ const result = await client.search('hello world', 10);
167
+ console.log(result.tweets);
168
+ ```
169
+
170
+ ## How it works
171
+
172
+ X uses GraphQL endpoints with rotating query IDs embedded in their client-side JavaScript bundles. x-reader auto-discovers these IDs by scraping the JS bundles, caching them locally with a 24-hour TTL. No manual ID updates needed.
173
+
174
+ If you get 404 errors, force a refresh:
175
+ ```bash
176
+ x-reader query-ids --refresh
177
+ ```
178
+
179
+ ## Architecture
180
+
181
+ ```
182
+ src/
183
+ ├── api/
184
+ │ ├── client.ts # Main API client (read-only operations)
185
+ │ ├── constants.ts # Bearer token, URLs, default query IDs
186
+ │ ├── features.ts # GraphQL feature flags per operation
187
+ │ ├── parser.ts # Response parsing (raw JSON -> Tweet/User)
188
+ │ ├── query-ids.ts # Auto-discovery of query IDs from x.com JS
189
+ │ └── types.ts # TypeScript interfaces
190
+ ├── cli/
191
+ │ └── index.ts # CLI entry point (commander)
192
+ ├── utils/
193
+ │ ├── auth.ts # Cookie resolution (env, config, bird compat)
194
+ │ └── format.ts # Output formatting
195
+ └── index.ts # Library exports
196
+ ```
197
+
198
+ ## Credits
199
+
200
+ - Inspired by [Bird CLI](https://github.com/steipete/bird) by [@steipete](https://x.com/steipete)
201
+ - Uses the same public bearer token as the X web client
202
+ - Query ID discovery mechanism reverse-engineered from Bird v0.8.0
203
+
204
+ ## License
205
+
206
+ MIT
@@ -0,0 +1,65 @@
1
+ /**
2
+ * XReader API Client — Read-only Twitter/X GraphQL client.
3
+ *
4
+ * Provides: search, user-tweets, tweet-detail, replies, bookmarks, user-lookup.
5
+ * Does NOT provide any write operations (tweet, like, retweet, follow, etc.)
6
+ */
7
+ import type { ClientOptions, TweetsResult, TweetResult, UserResult } from './types.js';
8
+ export declare class XReaderClient {
9
+ private authToken;
10
+ private ct0;
11
+ private cookieHeader;
12
+ private userAgent;
13
+ private timeoutMs?;
14
+ private quoteDepth;
15
+ private clientUuid;
16
+ constructor(options: ClientOptions);
17
+ private getHeaders;
18
+ private fetchWithTimeout;
19
+ private sleep;
20
+ private getQueryIds;
21
+ /**
22
+ * Try a request with multiple query IDs, auto-refresh on 404.
23
+ */
24
+ private tryWithQueryIds;
25
+ search(query: string, count?: number, options?: {
26
+ cursor?: string;
27
+ includeRaw?: boolean;
28
+ }): Promise<TweetsResult>;
29
+ getTweet(tweetId: string, options?: {
30
+ includeRaw?: boolean;
31
+ }): Promise<TweetResult>;
32
+ getReplies(tweetId: string, options?: {
33
+ includeRaw?: boolean;
34
+ }): Promise<TweetsResult>;
35
+ getUserTweets(userId: string, count?: number, options?: {
36
+ cursor?: string;
37
+ includeRaw?: boolean;
38
+ }): Promise<TweetsResult>;
39
+ getBookmarks(count?: number, options?: {
40
+ cursor?: string;
41
+ includeRaw?: boolean;
42
+ }): Promise<TweetsResult>;
43
+ getUserByUsername(username: string): Promise<UserResult>;
44
+ /**
45
+ * Search with automatic pagination to collect up to `count` tweets.
46
+ */
47
+ searchAll(query: string, count: number, options?: {
48
+ maxPages?: number;
49
+ includeRaw?: boolean;
50
+ }): Promise<TweetsResult>;
51
+ /**
52
+ * Get user tweets with pagination.
53
+ */
54
+ getUserTweetsAll(userId: string, count: number, options?: {
55
+ maxPages?: number;
56
+ includeRaw?: boolean;
57
+ }): Promise<TweetsResult>;
58
+ /**
59
+ * Get all bookmarks with pagination.
60
+ */
61
+ getBookmarksAll(count?: number, options?: {
62
+ maxPages?: number;
63
+ includeRaw?: boolean;
64
+ }): Promise<TweetsResult>;
65
+ }