scavio 0.12.0 → 0.14.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 +57 -12
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -10
- package/dist/index.d.ts +18 -10
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,16 +33,31 @@ const client = new Scavio({
|
|
|
33
33
|
baseUrl: "https://api.scavio.dev", // default
|
|
34
34
|
timeout: 30_000, // ms, default
|
|
35
35
|
maxRequestsPerSecond: 1, // 1-10, default 1
|
|
36
|
+
maxRetries: 2, // default 2, set 0 to disable
|
|
36
37
|
});
|
|
37
38
|
```
|
|
38
39
|
|
|
40
|
+
`maxRetries` is the number of extra attempts after the first request, applied
|
|
41
|
+
only to transient failures — HTTP 429, 500, 502, 503, 504 and network or timeout
|
|
42
|
+
errors. Backoff is exponential with full jitter, capped at 8s, and a
|
|
43
|
+
`Retry-After` header is honored when the API sends one. Non-transient errors
|
|
44
|
+
(400, 401, 402, 404) are never retried.
|
|
45
|
+
|
|
46
|
+
`maxRequestsPerSecond` throttles the client so it never sends more than N
|
|
47
|
+
requests in any one-second window. Your plan also has a server-side concurrency
|
|
48
|
+
limit on simultaneous in-flight requests: 1 on free and pay-as-you-go, 2 on
|
|
49
|
+
Project, 3 on Bootstrap, 5 on Startup, 10 on Growth.
|
|
50
|
+
|
|
39
51
|
## API Reference
|
|
40
52
|
|
|
41
53
|
### Google
|
|
42
54
|
|
|
43
|
-
|
|
44
|
-
passthrough); each costs 1 credit.
|
|
45
|
-
|
|
55
|
+
Each method hits its own `/api/v2/google*` endpoint and returns Google's full
|
|
56
|
+
response (raw passthrough); each costs 1 credit. Results come back as
|
|
57
|
+
`organic_results[]` with `link` and `snippet`. Geo and paging use `gl`, `hl`,
|
|
58
|
+
`start`, `google_domain` and `device` — the old v1 vocabulary (`light_request`,
|
|
59
|
+
`country_code`, `language`, `search_type`, `page`) does not exist on v2 and is
|
|
60
|
+
dropped server-side.
|
|
46
61
|
|
|
47
62
|
```typescript
|
|
48
63
|
// SERP search (includes the AI Overview when Google shows one)
|
|
@@ -129,6 +144,9 @@ await client.walmart.product({
|
|
|
129
144
|
|
|
130
145
|
### YouTube
|
|
131
146
|
|
|
147
|
+
Credit cost varies by endpoint: `transcript` costs 8; `streams` costs 3;
|
|
148
|
+
`search` and `shorts` cost 2; every other YouTube endpoint costs 1.
|
|
149
|
+
|
|
132
150
|
```typescript
|
|
133
151
|
// Search videos
|
|
134
152
|
await client.youtube.search({
|
|
@@ -176,6 +194,14 @@ await client.youtube.channelResolve({ channel: "@mkbhd" }); // handle/URL -> id
|
|
|
176
194
|
|
|
177
195
|
### Reddit
|
|
178
196
|
|
|
197
|
+
Every Reddit endpoint costs 1 credit.
|
|
198
|
+
|
|
199
|
+
`search()` takes only `query` and `cursor` — there is no result-type or sort
|
|
200
|
+
filter upstream, so anything else is dropped server-side. It returns
|
|
201
|
+
`data.results` with `next_cursor` and `has_more`. `post()` returns a flat post
|
|
202
|
+
object under `data` and carries no comments; use `postComments()` for those.
|
|
203
|
+
The subreddit and user feeds return `data.posts`.
|
|
204
|
+
|
|
179
205
|
```typescript
|
|
180
206
|
// Search posts
|
|
181
207
|
await client.reddit.search({ query: "typescript", cursor: "..." });
|
|
@@ -253,16 +279,20 @@ await client.linkedin.post({ post_id: "7488618410256523265" });
|
|
|
253
279
|
await client.linkedin.postComments({ post_id: "7488618410256523265", page: 1 });
|
|
254
280
|
```
|
|
255
281
|
|
|
256
|
-
|
|
282
|
+
Credit cost varies by endpoint: `job` costs 30; `personPosts`, `companyPosts`,
|
|
283
|
+
`searchJobs` and `postComments` cost 10 per page; `person`, `personAbout`,
|
|
284
|
+
`company` and `post` cost 1.
|
|
257
285
|
|
|
258
286
|
> **Retired endpoints.** The upstream provider withdrew the datasets behind
|
|
259
287
|
> `personContact`, `companyPeople`, `companyJobs`, `searchPeople` and
|
|
260
288
|
> `searchPosts`. They remain callable but always return HTTP 410 and are never
|
|
261
289
|
> billed. `company()` returns `featured_employees` (a small sample of staff), and
|
|
262
290
|
> `searchJobs()` with a company name substitutes for `companyJobs()`.
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
291
|
+
|
|
292
|
+
`personPosts`, `companyPosts` and `searchJobs` paginate: pass the previous
|
|
293
|
+
response's `next_cursor` as `cursor` to fetch the next page. `personPosts` also
|
|
294
|
+
takes `type` (`"posts"`, `"comments"` or `"reactions"`) to pick the feed.
|
|
295
|
+
`postComments` pages with a 1-based `page` instead.
|
|
266
296
|
|
|
267
297
|
### TikTok
|
|
268
298
|
|
|
@@ -282,8 +312,8 @@ await client.tiktok.videoComments({ video_id: "vid123", count: 20 });
|
|
|
282
312
|
// Comment replies
|
|
283
313
|
await client.tiktok.commentReplies({ video_id: "vid123", comment_id: "c456" });
|
|
284
314
|
|
|
285
|
-
// Search videos
|
|
286
|
-
await client.tiktok.searchVideos({ keyword: "dance", sort_type: "
|
|
315
|
+
// Search videos (sort_type: '0' = relevance, '1' = most likes)
|
|
316
|
+
await client.tiktok.searchVideos({ keyword: "dance", sort_type: "1" });
|
|
287
317
|
|
|
288
318
|
// Search users
|
|
289
319
|
await client.tiktok.searchUsers({ keyword: "cooking" });
|
|
@@ -362,8 +392,16 @@ await client.tiktokShop.resolve({ url: "https://vt.tiktok.com/ZT2AHoGsE/" });
|
|
|
362
392
|
|
|
363
393
|
### Instagram
|
|
364
394
|
|
|
365
|
-
Credit cost varies by endpoint
|
|
366
|
-
|
|
395
|
+
Credit cost varies by endpoint, in three tiers:
|
|
396
|
+
|
|
397
|
+
| Credits | Methods |
|
|
398
|
+
|---|---|
|
|
399
|
+
| 2 | `userPosts` |
|
|
400
|
+
| 8 | `post`, `commentReplies` |
|
|
401
|
+
| 10 | `profile`, `userReels`, `userTagged`, `userStories`, `postComments`, `searchUsers`, `searchHashtags`, `userFollowers`, `userFollowings` |
|
|
402
|
+
|
|
403
|
+
The 10-credit endpoints run two upstream providers in parallel and bill both
|
|
404
|
+
legs; the 8-credit ones have no fallback leg to hedge against.
|
|
367
405
|
|
|
368
406
|
```typescript
|
|
369
407
|
// User profile
|
|
@@ -420,12 +458,19 @@ All error classes:
|
|
|
420
458
|
| Class | HTTP Status | Description |
|
|
421
459
|
|-------|------------|-------------|
|
|
422
460
|
| `MissingAPIKeyError` | — | No API key provided |
|
|
461
|
+
| `ScavioConnectionError` | — | Request never reached the API (DNS, reset, TLS) |
|
|
462
|
+
| `ScavioTimeoutError` | — | Request exceeded the configured `timeout` |
|
|
463
|
+
| `BadRequestError` | 400 | Invalid request parameters |
|
|
423
464
|
| `InvalidAPIKeyError` | 401 | Invalid API key |
|
|
424
465
|
| `InsufficientCreditsError` | 402 | No credits remaining |
|
|
425
|
-
| `
|
|
466
|
+
| `NotFoundError` | 404 | No data upstream for that id (see TikTok Shop above) |
|
|
426
467
|
| `RateLimitError` | 429 | Rate limit exceeded |
|
|
427
468
|
| `ScavioAPIError` | other | Catch-all (has `.statusCode`) |
|
|
428
469
|
|
|
470
|
+
Every class extends `ScavioError`, so `catch (e) { if (e instanceof ScavioError) }`
|
|
471
|
+
matches all of them. All except `MissingAPIKeyError`, `ScavioConnectionError` and
|
|
472
|
+
`ScavioTimeoutError` carry `.statusCode` and `.responseBody`.
|
|
473
|
+
|
|
429
474
|
## Runtime Support
|
|
430
475
|
|
|
431
476
|
- Node.js 18+
|
package/dist/index.cjs
CHANGED
|
@@ -398,12 +398,17 @@ var RedditNamespace = class {
|
|
|
398
398
|
this.client = client;
|
|
399
399
|
}
|
|
400
400
|
client;
|
|
401
|
+
/** Returns `data.results` plus `next_cursor` / `has_more` (not `data.posts`). */
|
|
401
402
|
async search(options) {
|
|
402
403
|
return this.client._post("/api/v1/reddit/search", options);
|
|
403
404
|
}
|
|
404
405
|
async searchSuggestions(options) {
|
|
405
406
|
return this.client._post("/api/v1/reddit/search/suggestions", options);
|
|
406
407
|
}
|
|
408
|
+
/**
|
|
409
|
+
* Returns a flat post object under `data` (post_id, title, text, url,
|
|
410
|
+
* subreddit, author, score, ...). Comments are a separate call.
|
|
411
|
+
*/
|
|
407
412
|
async post(options) {
|
|
408
413
|
return this.client._post("/api/v1/reddit/post", options);
|
|
409
414
|
}
|