scavio 0.7.0 → 0.9.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 +76 -14
- package/dist/index.cjs +125 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +187 -23
- package/dist/index.d.ts +187 -23
- package/dist/index.js +125 -15
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Scavio
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for the [Scavio Search API](https://scavio.dev) — real-time Google, Amazon, Walmart, YouTube, Reddit, TikTok, Instagram,
|
|
3
|
+
TypeScript SDK for the [Scavio Search API](https://scavio.dev) — real-time Google, Amazon, Walmart, YouTube, Reddit, TikTok, TikTok Shop, Instagram, X, and LinkedIn data.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -179,27 +179,27 @@ await client.reddit.popular();
|
|
|
179
179
|
await client.reddit.trending();
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
-
###
|
|
182
|
+
### X
|
|
183
183
|
|
|
184
184
|
```typescript
|
|
185
185
|
// Search tweets and people
|
|
186
|
-
await client.
|
|
186
|
+
await client.x.search({ search: "artificial intelligence", search_type: "Latest" });
|
|
187
187
|
|
|
188
188
|
// Tweet detail, comments, and retweeters
|
|
189
|
-
await client.
|
|
190
|
-
await client.
|
|
191
|
-
await client.
|
|
189
|
+
await client.x.tweet({ tweet_id: "1808168603721650364" });
|
|
190
|
+
await client.x.tweetComments({ tweet_id: "1808168603721650364", rank: "top" });
|
|
191
|
+
await client.x.tweetRetweeters({ tweet_id: "1808168603721650364" });
|
|
192
192
|
|
|
193
193
|
// User profile and feeds
|
|
194
|
-
await client.
|
|
195
|
-
await client.
|
|
196
|
-
await client.
|
|
197
|
-
await client.
|
|
198
|
-
await client.
|
|
199
|
-
await client.
|
|
194
|
+
await client.x.user({ screen_name: "elonmusk" });
|
|
195
|
+
await client.x.userTweets({ screen_name: "elonmusk" });
|
|
196
|
+
await client.x.userReplies({ screen_name: "elonmusk" });
|
|
197
|
+
await client.x.userMedia({ screen_name: "elonmusk" });
|
|
198
|
+
await client.x.userFollowers({ screen_name: "elonmusk" });
|
|
199
|
+
await client.x.userFollowings({ screen_name: "elonmusk" });
|
|
200
200
|
|
|
201
201
|
// Trending topics
|
|
202
|
-
await client.
|
|
202
|
+
await client.x.trending({ country: "UnitedStates" });
|
|
203
203
|
```
|
|
204
204
|
|
|
205
205
|
### LinkedIn
|
|
@@ -265,8 +265,70 @@ await client.tiktok.userFollowers({ sec_user_id: "abc123" });
|
|
|
265
265
|
await client.tiktok.userFollowings({ sec_user_id: "abc123" });
|
|
266
266
|
```
|
|
267
267
|
|
|
268
|
+
### TikTok Shop
|
|
269
|
+
|
|
270
|
+
Every TikTok Shop endpoint costs 1 credit. Two limits to design around:
|
|
271
|
+
|
|
272
|
+
- `product()` resolves only about 44% of the product ids returned by `search()`.
|
|
273
|
+
Upstream has no detail data for the rest, so an HTTP 404 is a normal outcome, not an
|
|
274
|
+
error — skip the item instead of retrying. Search to product is not a reliable
|
|
275
|
+
pipeline. `product()` **throws** `NotFoundError` on that 404 (there is no `data`
|
|
276
|
+
field in the body to test), so a loop over search ids must catch it:
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import { NotFoundError } from "scavio";
|
|
280
|
+
|
|
281
|
+
for (const productId of productIds) {
|
|
282
|
+
try {
|
|
283
|
+
const detail = await client.tiktokShop.product({ product_id: productId });
|
|
284
|
+
} catch (e) {
|
|
285
|
+
if (e instanceof NotFoundError) continue; // no detail upstream; skip
|
|
286
|
+
throw e;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
`productReviews()` often works for ids `product()` cannot resolve: of 8 such ids
|
|
292
|
+
tested, 8 returned HTTP 200 and 7 carried at least one review, so it is a useful
|
|
293
|
+
fallback source of product detail.
|
|
294
|
+
- `product()` does not return a price; upstream masks it on the product page. Exact
|
|
295
|
+
prices come from `search()`, `shopProducts()`, and `categoryProducts()`.
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
// Search products (US catalog, exact prices, cursor pagination)
|
|
299
|
+
await client.tiktokShop.search({ search: "phone case" });
|
|
300
|
+
|
|
301
|
+
// Keyword suggestions (8 regions)
|
|
302
|
+
await client.tiktokShop.searchSuggestions({ search: "wireless", region: "US" });
|
|
303
|
+
|
|
304
|
+
// Product detail (no price; a 404 is normal, see above)
|
|
305
|
+
await client.tiktokShop.product({ product_id: "1732293553906094315" });
|
|
306
|
+
|
|
307
|
+
// Product reviews (up to 200 per call)
|
|
308
|
+
await client.tiktokShop.productReviews({
|
|
309
|
+
product_id: "1732293553906094315",
|
|
310
|
+
page_size: 200,
|
|
311
|
+
sort: "relevant",
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Category tree (28 top-level, 240 nodes)
|
|
315
|
+
await client.tiktokShop.categories();
|
|
316
|
+
|
|
317
|
+
// Products in a category (US and GB only)
|
|
318
|
+
await client.tiktokShop.categoryProducts({ category_id: "601450" });
|
|
319
|
+
|
|
320
|
+
// A shop's catalog, 30 per page
|
|
321
|
+
await client.tiktokShop.shopProducts({ shop_id: "7495514739648989419" });
|
|
322
|
+
|
|
323
|
+
// Resolve any TikTok Shop URL or share link to a product_id / shop_id
|
|
324
|
+
await client.tiktokShop.resolve({ url: "https://vt.tiktok.com/ZT2AHoGsE/" });
|
|
325
|
+
```
|
|
326
|
+
|
|
268
327
|
### Instagram
|
|
269
328
|
|
|
329
|
+
Credit cost varies by endpoint: `userPosts` costs 2 credits, every other
|
|
330
|
+
Instagram endpoint costs 8.
|
|
331
|
+
|
|
270
332
|
```typescript
|
|
271
333
|
// User profile
|
|
272
334
|
await client.instagram.profile({ username: "instagram" });
|
|
@@ -349,7 +411,7 @@ MIT
|
|
|
349
411
|
- [Amazon Product API](https://scavio.dev/amazon-product-api) and [Walmart Product API](https://scavio.dev/walmart-product-api) — product search and details
|
|
350
412
|
- [YouTube API](https://scavio.dev/youtube-transcript-api), [TikTok API](https://scavio.dev/tiktok-api), and [Instagram API](https://scavio.dev/instagram-api) — video and social media data
|
|
351
413
|
- [Reddit API](https://scavio.dev/reddit-api) — posts and threaded comments
|
|
352
|
-
- [
|
|
414
|
+
- [X API](https://scavio.dev/docs/x-search) and [LinkedIn API](https://scavio.dev/docs/linkedin-person) — tweets, profiles, companies, and jobs
|
|
353
415
|
|
|
354
416
|
Teams choosing between providers can [compare Scavio vs alternatives](https://scavio.dev/compare) side by side.
|
|
355
417
|
|
package/dist/index.cjs
CHANGED
|
@@ -466,6 +466,114 @@ var TikTokNamespace = class {
|
|
|
466
466
|
}
|
|
467
467
|
};
|
|
468
468
|
|
|
469
|
+
// src/namespaces/tiktok-shop.ts
|
|
470
|
+
var TikTokShopNamespace = class {
|
|
471
|
+
constructor(client) {
|
|
472
|
+
this.client = client;
|
|
473
|
+
}
|
|
474
|
+
client;
|
|
475
|
+
/**
|
|
476
|
+
* Search TikTok Shop products by keyword (US catalog), up to 30 per page with
|
|
477
|
+
* exact prices, ratings, and shop details. Paginate with next_cursor and dedupe
|
|
478
|
+
* by product_id across pages.
|
|
479
|
+
*
|
|
480
|
+
* This is one of the three endpoints that return exact prices; tiktokShop.product()
|
|
481
|
+
* does not return a price. A product_id returned here is not guaranteed to resolve
|
|
482
|
+
* on tiktokShop.product() - only about 44% do.
|
|
483
|
+
*/
|
|
484
|
+
async search(options) {
|
|
485
|
+
return this.client._post("/api/v1/tiktok-shop/search", options);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Keyword autocomplete and expansion for a partial query, across 8 marketplace
|
|
489
|
+
* regions. Suggestions are not guaranteed prefix matches: a misspelling returns
|
|
490
|
+
* typo corrections, and results can include brand and shop names.
|
|
491
|
+
*/
|
|
492
|
+
async searchSuggestions(options) {
|
|
493
|
+
return this.client._post("/api/v1/tiktok-shop/search/suggestions", options);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Full product detail: description, images, variants with stock, shipping, shop
|
|
497
|
+
* profile, category path, and top reviews.
|
|
498
|
+
*
|
|
499
|
+
* Two limits worth knowing before you build on this:
|
|
500
|
+
*
|
|
501
|
+
* 1. It resolves only about 44% of the product ids returned by tiktokShop.search().
|
|
502
|
+
* Upstream has no detail data for the rest, so an HTTP 404 is a normal outcome,
|
|
503
|
+
* not an error. Skip the item rather than retrying - retries do not help and no
|
|
504
|
+
* other region carries it. Search to product is not a reliable pipeline.
|
|
505
|
+
*
|
|
506
|
+
* This method throws `NotFoundError` on that 404 (there is no `data` field in
|
|
507
|
+
* the response body to test), so a loop over search ids must catch it or it
|
|
508
|
+
* dies on the first miss:
|
|
509
|
+
*
|
|
510
|
+
* ```ts
|
|
511
|
+
* import { NotFoundError } from "scavio";
|
|
512
|
+
*
|
|
513
|
+
* for (const productId of productIds) {
|
|
514
|
+
* try {
|
|
515
|
+
* const detail = await client.tiktokShop.product({ product_id: productId });
|
|
516
|
+
* } catch (e) {
|
|
517
|
+
* if (e instanceof NotFoundError) continue; // no detail upstream; skip
|
|
518
|
+
* throw e;
|
|
519
|
+
* }
|
|
520
|
+
* }
|
|
521
|
+
* ```
|
|
522
|
+
*
|
|
523
|
+
* tiktokShop.productReviews() often works for ids product() cannot resolve: of
|
|
524
|
+
* 8 such ids tested, 8 returned HTTP 200 and 7 carried at least one review, so
|
|
525
|
+
* it is a useful fallback source of product detail.
|
|
526
|
+
* 2. It does NOT return a price. Upstream masks the price on the product page.
|
|
527
|
+
* Exact prices come from tiktokShop.search(), tiktokShop.shopProducts(), and
|
|
528
|
+
* tiktokShop.categoryProducts().
|
|
529
|
+
*/
|
|
530
|
+
async product(options) {
|
|
531
|
+
return this.client._post("/api/v1/tiktok-shop/product", options);
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Paginated product reviews with text, images, star histogram, and
|
|
535
|
+
* verified-purchase flags, up to 200 per call. total_reviews drifts between calls
|
|
536
|
+
* and must not be used to compute a page count; page with has_more instead.
|
|
537
|
+
*/
|
|
538
|
+
async productReviews(options) {
|
|
539
|
+
return this.client._post("/api/v1/tiktok-shop/product/reviews", options);
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* The global TikTok Shop category tree: 28 top-level categories, 240 nodes, two
|
|
543
|
+
* levels deep. Category ids are identical in every region and names are always
|
|
544
|
+
* English.
|
|
545
|
+
*/
|
|
546
|
+
async categories() {
|
|
547
|
+
return this.client._post("/api/v1/tiktok-shop/categories", {});
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Products listed under a category id from tiktokShop.categories(), with exact
|
|
551
|
+
* prices. Page size is inconsistent upstream (15 to 20 per page), so always
|
|
552
|
+
* paginate with next_cursor rather than assuming a fixed page size. Category
|
|
553
|
+
* listings are shallow: after a few pages the source stops returning new products
|
|
554
|
+
* and has_more turns false, which is the end of the listing rather than an error.
|
|
555
|
+
*/
|
|
556
|
+
async categoryProducts(options) {
|
|
557
|
+
return this.client._post("/api/v1/tiktok-shop/category/products", options);
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* A shop's product catalog, 30 per page, with exact prices. Shop follower count,
|
|
561
|
+
* location, and shop-level rating are not available here; call
|
|
562
|
+
* tiktokShop.product() for the full shop profile.
|
|
563
|
+
*/
|
|
564
|
+
async shopProducts(options) {
|
|
565
|
+
return this.client._post("/api/v1/tiktok-shop/shop/products", options);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Resolve any TikTok Shop URL or share link to a product_id or shop_id, ready to
|
|
569
|
+
* pass to the other methods. Accepts canonical product and store pages,
|
|
570
|
+
* tiktok.com/view links, affiliate share links, and vt.tiktok.com short links.
|
|
571
|
+
*/
|
|
572
|
+
async resolve(options) {
|
|
573
|
+
return this.client._post("/api/v1/tiktok-shop/resolve", options);
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
|
|
469
577
|
// src/namespaces/instagram.ts
|
|
470
578
|
var InstagramNamespace = class {
|
|
471
579
|
constructor(client) {
|
|
@@ -601,44 +709,44 @@ var YouTubeNamespace = class {
|
|
|
601
709
|
}
|
|
602
710
|
};
|
|
603
711
|
|
|
604
|
-
// src/namespaces/
|
|
605
|
-
var
|
|
712
|
+
// src/namespaces/x.ts
|
|
713
|
+
var XNamespace = class {
|
|
606
714
|
constructor(client) {
|
|
607
715
|
this.client = client;
|
|
608
716
|
}
|
|
609
717
|
client;
|
|
610
718
|
async search(options) {
|
|
611
|
-
return this.client._post("/api/v1/
|
|
719
|
+
return this.client._post("/api/v1/x/search", options);
|
|
612
720
|
}
|
|
613
721
|
async tweet(options) {
|
|
614
|
-
return this.client._post("/api/v1/
|
|
722
|
+
return this.client._post("/api/v1/x/tweet", options);
|
|
615
723
|
}
|
|
616
724
|
async tweetComments(options) {
|
|
617
|
-
return this.client._post("/api/v1/
|
|
725
|
+
return this.client._post("/api/v1/x/tweet/comments", options);
|
|
618
726
|
}
|
|
619
727
|
async tweetRetweeters(options) {
|
|
620
|
-
return this.client._post("/api/v1/
|
|
728
|
+
return this.client._post("/api/v1/x/tweet/retweeters", options);
|
|
621
729
|
}
|
|
622
730
|
async user(options) {
|
|
623
|
-
return this.client._post("/api/v1/
|
|
731
|
+
return this.client._post("/api/v1/x/user", options);
|
|
624
732
|
}
|
|
625
733
|
async userTweets(options) {
|
|
626
|
-
return this.client._post("/api/v1/
|
|
734
|
+
return this.client._post("/api/v1/x/user/tweets", options);
|
|
627
735
|
}
|
|
628
736
|
async userReplies(options) {
|
|
629
|
-
return this.client._post("/api/v1/
|
|
737
|
+
return this.client._post("/api/v1/x/user/replies", options);
|
|
630
738
|
}
|
|
631
739
|
async userMedia(options) {
|
|
632
|
-
return this.client._post("/api/v1/
|
|
740
|
+
return this.client._post("/api/v1/x/user/media", options);
|
|
633
741
|
}
|
|
634
742
|
async userFollowers(options) {
|
|
635
|
-
return this.client._post("/api/v1/
|
|
743
|
+
return this.client._post("/api/v1/x/user/followers", options);
|
|
636
744
|
}
|
|
637
745
|
async userFollowings(options) {
|
|
638
|
-
return this.client._post("/api/v1/
|
|
746
|
+
return this.client._post("/api/v1/x/user/followings", options);
|
|
639
747
|
}
|
|
640
748
|
async trending(options = {}) {
|
|
641
|
-
return this.client._post("/api/v1/
|
|
749
|
+
return this.client._post("/api/v1/x/trending", options);
|
|
642
750
|
}
|
|
643
751
|
};
|
|
644
752
|
|
|
@@ -700,8 +808,9 @@ var Scavio = class {
|
|
|
700
808
|
youtube;
|
|
701
809
|
reddit;
|
|
702
810
|
tiktok;
|
|
811
|
+
tiktokShop;
|
|
703
812
|
instagram;
|
|
704
|
-
|
|
813
|
+
x;
|
|
705
814
|
linkedin;
|
|
706
815
|
apiKey;
|
|
707
816
|
baseUrl;
|
|
@@ -727,8 +836,9 @@ var Scavio = class {
|
|
|
727
836
|
this.youtube = new YouTubeNamespace(this);
|
|
728
837
|
this.reddit = new RedditNamespace(this);
|
|
729
838
|
this.tiktok = new TikTokNamespace(this);
|
|
839
|
+
this.tiktokShop = new TikTokShopNamespace(this);
|
|
730
840
|
this.instagram = new InstagramNamespace(this);
|
|
731
|
-
this.
|
|
841
|
+
this.x = new XNamespace(this);
|
|
732
842
|
this.linkedin = new LinkedInNamespace(this);
|
|
733
843
|
}
|
|
734
844
|
/** @internal */
|