fxtwitter 1.0.0 → 2.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 +111 -31
- package/dist/LICENSE-citty +21 -0
- package/dist/THIRD-PARTY-LICENSES-citty.md +33 -0
- package/dist/cli.mjs +880 -0
- package/dist/{v1-KUPCoHD9.mjs → http-BTdKgEdX.mjs} +1 -56
- package/dist/http-CidaL0TV.d.cts +24 -0
- package/dist/http-CidaL0TV.d.mts +24 -0
- package/dist/{v1-Da3KbdIz.cjs → http-Cs4GJeg-.cjs} +2 -57
- package/dist/index.cjs +48 -2
- package/dist/index.d.cts +40 -2
- package/dist/index.d.mts +40 -2
- package/dist/index.mjs +45 -2
- package/dist/v1-BFKgLuJi.cjs +92 -0
- package/dist/v1-ByqsBlpO.mjs +87 -0
- package/dist/v1.cjs +1 -1
- package/dist/v1.d.cts +252 -1
- package/dist/v1.d.mts +252 -1
- package/dist/v1.mjs +1 -1
- package/dist/v2.cjs +183 -0
- package/dist/v2.d.cts +685 -0
- package/dist/v2.d.mts +685 -0
- package/dist/v2.mjs +181 -0
- package/package.json +13 -1
- package/dist/v1-BKUGwGbc.d.cts +0 -267
- package/dist/v1-BKUGwGbc.d.mts +0 -267
package/README.md
CHANGED
|
@@ -13,33 +13,61 @@ Typed wrapper for the [FxTwitter](https://github.com/FxEmbed/FxEmbed) API.
|
|
|
13
13
|
npm install fxtwitter
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
## CLI
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
npx fxtwitter status 20
|
|
20
|
+
npx fxtwitter status "https://x.com/jack/status/20" --pretty
|
|
21
|
+
npx fxtwitter profile @jack --api v1
|
|
22
|
+
npx fxtwitter search "from:jack puppies" | jq '.results'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The CLI uses API v2 by default. Use `--api v1` with `status` or `profile`. Search is available in v2. Profile handles can include a leading `@`.
|
|
26
|
+
|
|
27
|
+
Successful commands write compact JSON to stdout. Use `--pretty` to indent it. Errors go to stderr and exit with a nonzero status.
|
|
28
|
+
|
|
29
|
+
| Option | Description |
|
|
30
|
+
| ------ | ----------- |
|
|
31
|
+
| `--base-url <url>` | Override the API base URL |
|
|
32
|
+
| `--timeout <ms>` | Set the request timeout |
|
|
33
|
+
| `--retry <count>` | Set the retry count (use `0` to disable retries) |
|
|
34
|
+
| `--retry-delay <ms>` | Set the delay between retries |
|
|
35
|
+
| `-h, --help` | Show commands and options. Use `fxtwitter status --help` for help with a specific command |
|
|
36
|
+
|
|
16
37
|
## Usage
|
|
17
38
|
|
|
18
39
|
```ts
|
|
19
|
-
import {
|
|
40
|
+
import { FxTwitterV2 } from "fxtwitter/v2";
|
|
20
41
|
|
|
21
|
-
const fx = new
|
|
42
|
+
const fx = new FxTwitterV2();
|
|
22
43
|
|
|
23
|
-
const {
|
|
24
|
-
const { user } = await fx.
|
|
44
|
+
const { status } = await fx.getStatus("20");
|
|
45
|
+
const { user } = await fx.getProfile("X");
|
|
46
|
+
const { results } = await fx.search("puppies");
|
|
25
47
|
```
|
|
26
48
|
|
|
27
|
-
|
|
49
|
+
Each version ships under its own subpath, where its types are exported
|
|
50
|
+
alongside the client:
|
|
28
51
|
|
|
29
52
|
```ts
|
|
30
|
-
import {
|
|
53
|
+
import { FxTwitterV2, type TwitterStatus } from "fxtwitter/v2";
|
|
54
|
+
import { FxTwitterV1, type Tweet } from "fxtwitter/v1";
|
|
31
55
|
```
|
|
32
56
|
|
|
33
|
-
|
|
34
|
-
|
|
57
|
+
If you need both at once, `FxTwitter` bundles them. `v1` is only constructed —
|
|
58
|
+
and so only warns — on first access:
|
|
35
59
|
|
|
36
60
|
```ts
|
|
37
|
-
import {
|
|
61
|
+
import { FxTwitter } from "fxtwitter";
|
|
62
|
+
|
|
63
|
+
const fx = new FxTwitter({ v1: { silenceDeprecationWarning: true } });
|
|
64
|
+
await fx.v2.getStatus("20");
|
|
65
|
+
await fx.v1.getStatus("20");
|
|
38
66
|
```
|
|
39
67
|
|
|
40
|
-
##
|
|
68
|
+
## Options
|
|
41
69
|
|
|
42
|
-
|
|
70
|
+
Every client takes the same options:
|
|
43
71
|
|
|
44
72
|
| Option | Type | Default | Description |
|
|
45
73
|
| --- | --- | --- | --- |
|
|
@@ -50,13 +78,15 @@ import { FxTwitterV1 } from "fxtwitter/v1";
|
|
|
50
78
|
| `retryDelay` | `number` | `0` | Delay between retries, in ms |
|
|
51
79
|
| `fetch` | `typeof fetch` | global `fetch` | Custom fetch implementation |
|
|
52
80
|
|
|
81
|
+
Every method takes an optional `signal` for per-call cancellation.
|
|
82
|
+
|
|
53
83
|
> The API requires a `User-Agent` identifying the caller and answers `401`
|
|
54
84
|
> without one. When you don't set one, a header describing the current runtime
|
|
55
85
|
> is sent — `Node.js/22.16.0`, `Bun/1.3.0`, `Cloudflare-Workers` and so on.
|
|
56
86
|
> Set your own to identify your app instead:
|
|
57
87
|
>
|
|
58
88
|
> ```ts
|
|
59
|
-
> new
|
|
89
|
+
> new FxTwitterV2({
|
|
60
90
|
> headers: { "User-Agent": "MyApp/1.0 (+https://example.com)" },
|
|
61
91
|
> });
|
|
62
92
|
> ```
|
|
@@ -64,14 +94,69 @@ import { FxTwitterV1 } from "fxtwitter/v1";
|
|
|
64
94
|
> Nothing is sent in browsers, where `User-Agent` is a forbidden header and the
|
|
65
95
|
> browser supplies its own.
|
|
66
96
|
|
|
67
|
-
|
|
97
|
+
## v2
|
|
98
|
+
|
|
99
|
+
### `new FxTwitterV2(options?)`
|
|
100
|
+
|
|
101
|
+
| Method | Returns |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| `getStatus(id, options?)` | A single post |
|
|
104
|
+
| `getThread(id, options?)` | A post with its unrolled thread |
|
|
105
|
+
| `getConversation(id, options?)` | A post, its thread, and ranked replies |
|
|
106
|
+
| `getStatusReposts(id, options?)` | Users who reposted a post |
|
|
107
|
+
| `getStatusQuotes(id, options?)` | Posts quoting a post |
|
|
108
|
+
| `getProfile(handle, options?)` | A user profile |
|
|
109
|
+
| `getProfileStatuses(handle, options?)` | A user's posts |
|
|
110
|
+
| `getProfileArticles(handle, options?)` | A user's long-form articles |
|
|
111
|
+
| `getProfileMedia(handle, options?)` | A user's posts containing media |
|
|
112
|
+
| `getProfileAbout(handle, options?)` | Account metadata |
|
|
113
|
+
| `getProfileFollowers(handle, options?)` | A user's followers |
|
|
114
|
+
| `getProfileFollowing(handle, options?)` | Accounts a user follows |
|
|
115
|
+
| `search(query, options?)` | Post search results |
|
|
116
|
+
| `typeahead(query, options?)` | Autocomplete suggestions |
|
|
117
|
+
| `trends(options?)` | Trending topics |
|
|
118
|
+
|
|
119
|
+
Common options: `count` and `cursor` paginate list endpoints, `lang` requests an
|
|
120
|
+
inline translation, and `aboutAccount` adds `about_account` to an author.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
// Paginate
|
|
124
|
+
let cursor: string | undefined;
|
|
125
|
+
do {
|
|
126
|
+
const page = await fx.search("puppies", { feed: "top", count: 50, cursor });
|
|
127
|
+
cursor = page.cursor.bottom ?? undefined;
|
|
128
|
+
} while (cursor);
|
|
129
|
+
|
|
130
|
+
// Look a profile up by numeric ID
|
|
131
|
+
import { byUserId } from "fxtwitter/v2";
|
|
132
|
+
await fx.getProfile(byUserId("783214"));
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The list endpoints report "no results" as a `404` carrying an otherwise normal
|
|
136
|
+
body. An empty page is a result rather than an error, so it resolves with
|
|
137
|
+
`results: []`. The API uses that same `404` for an unknown handle, which it does
|
|
138
|
+
not distinguish from an empty timeline.
|
|
139
|
+
|
|
140
|
+
`getProfileStatuses` resolves to `null` when `since` is set without a `cursor`
|
|
141
|
+
and nothing is newer — the API's documented `204`. Every other method either
|
|
142
|
+
resolves with a body or throws.
|
|
143
|
+
|
|
144
|
+
## v1
|
|
145
|
+
|
|
146
|
+
> **Deprecated.** v1 is kept only for backwards compatibility and does not
|
|
147
|
+
> receive new features — use [v2](#v2) instead. Constructing `FxTwitterV1`
|
|
148
|
+
> emits a one-time `DeprecationWarning` (so `--no-deprecation` and
|
|
149
|
+
> `--throw-deprecation` apply); pass `silenceDeprecationWarning: true` to
|
|
150
|
+
> suppress it. `FxTwitter`'s `v1` property only constructs the client, and so
|
|
151
|
+
> only warns, on first access.
|
|
152
|
+
|
|
153
|
+
### `new FxTwitterV1(options?)`
|
|
154
|
+
|
|
155
|
+
#### `getStatus(id, options?)`
|
|
68
156
|
|
|
69
157
|
Fetches a single status by its snowflake ID.
|
|
70
158
|
|
|
71
159
|
```ts
|
|
72
|
-
const { tweet } = await fx.getStatus("20");
|
|
73
|
-
|
|
74
|
-
// Translate the status
|
|
75
160
|
const { tweet } = await fx.getStatus("20", { translateTo: "es" });
|
|
76
161
|
tweet?.translation?.text;
|
|
77
162
|
```
|
|
@@ -80,12 +165,11 @@ tweet?.translation?.text;
|
|
|
80
165
|
| --- | --- | --- |
|
|
81
166
|
| `translateTo` | `string` | Target language — an ISO 639-1 code (`es`) or locale (`zh-cn`). Adds `translation` to the status |
|
|
82
167
|
| `screenName` | `string` | Author handle, for a readable URL. The API resolves the status from `id` alone and never checks it |
|
|
83
|
-
| `signal` | `AbortSignal` | Per-call cancellation |
|
|
84
168
|
|
|
85
169
|
Resolves to `{ code, message, tweet }`. `tweet` is `null` when the status could
|
|
86
170
|
not be retrieved.
|
|
87
171
|
|
|
88
|
-
|
|
172
|
+
#### `getUser(handle, options?)`
|
|
89
173
|
|
|
90
174
|
Fetches a user profile by handle, without a leading `@`.
|
|
91
175
|
|
|
@@ -93,15 +177,19 @@ Fetches a user profile by handle, without a leading `@`.
|
|
|
93
177
|
const { user } = await fx.getUser("jack");
|
|
94
178
|
```
|
|
95
179
|
|
|
96
|
-
| Option | Type | Description |
|
|
97
|
-
| --- | --- | --- |
|
|
98
|
-
| `signal` | `AbortSignal` | Per-call cancellation |
|
|
99
|
-
|
|
100
180
|
Resolves to `{ code, message, user, reason? }`. `user` is absent when the
|
|
101
181
|
profile could not be retrieved, and `reason` is `"suspended"` for a suspended
|
|
102
182
|
account.
|
|
103
183
|
|
|
104
|
-
|
|
184
|
+
On success, `code` mirrors the HTTP status and `message` is one of `OK`,
|
|
185
|
+
`PRIVATE_TWEET`, `NOT_FOUND`, `UPSTREAM_UNAVAILABLE` or `API_FAIL`.
|
|
186
|
+
|
|
187
|
+
Malformed input is rejected before a request is sent, because v1 answers those
|
|
188
|
+
cases with HTML or a redirect rather than JSON: a status ID must be 2-20 digits,
|
|
189
|
+
and a handle passed to `getUser` must match `\w{1,15}`. A well-formed handle
|
|
190
|
+
that does not exist is a normal `404`.
|
|
191
|
+
|
|
192
|
+
## Errors
|
|
105
193
|
|
|
106
194
|
HTTP 4xx/5xx, network failures, timeouts, invalid input, and non-JSON responses
|
|
107
195
|
are thrown as `FxTwitterError`:
|
|
@@ -122,18 +210,10 @@ try {
|
|
|
122
210
|
}
|
|
123
211
|
```
|
|
124
212
|
|
|
125
|
-
On success, `code` mirrors the HTTP status and `message` is one of `OK`,
|
|
126
|
-
`PRIVATE_TWEET`, `NOT_FOUND`, `UPSTREAM_UNAVAILABLE` or `API_FAIL`.
|
|
127
|
-
|
|
128
213
|
For a network failure or a timeout there is no response, so `status`, `code`
|
|
129
214
|
and `body` are all `undefined` and `message` is a generic description. The
|
|
130
215
|
original error is still available as `cause`.
|
|
131
216
|
|
|
132
|
-
Malformed input is rejected before a request is sent, because the API answers
|
|
133
|
-
those cases with HTML or a redirect rather than JSON: a status ID must be 2-20
|
|
134
|
-
digits, and a handle passed to `getUser` must match `\w{1,15}`. A well-formed
|
|
135
|
-
handle that does not exist is a normal `404`.
|
|
136
|
-
|
|
137
217
|
## Requirements
|
|
138
218
|
|
|
139
219
|
- Node.js >= 22
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Pooya Parsa <pooya@pi0.io>
|
|
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.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Licenses of Bundled Dependencies
|
|
2
|
+
|
|
3
|
+
The published artifact additionally contains code with the following licenses:
|
|
4
|
+
MIT
|
|
5
|
+
|
|
6
|
+
# Bundled Dependencies
|
|
7
|
+
|
|
8
|
+
## scule
|
|
9
|
+
|
|
10
|
+
License: MIT
|
|
11
|
+
Repository: https://github.com/unjs/scule
|
|
12
|
+
|
|
13
|
+
> MIT License
|
|
14
|
+
>
|
|
15
|
+
> Copyright (c) Pooya Parsa <pooya@pi0.io>
|
|
16
|
+
>
|
|
17
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
18
|
+
> of this software and associated documentation files (the "Software"), to deal
|
|
19
|
+
> in the Software without restriction, including without limitation the rights
|
|
20
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
21
|
+
> copies of the Software, and to permit persons to whom the Software is
|
|
22
|
+
> furnished to do so, subject to the following conditions:
|
|
23
|
+
>
|
|
24
|
+
> The above copyright notice and this permission notice shall be included in all
|
|
25
|
+
> copies or substantial portions of the Software.
|
|
26
|
+
>
|
|
27
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
28
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
29
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
30
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
31
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
32
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
33
|
+
> SOFTWARE.
|