scavio 0.23.0 → 0.24.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 CHANGED
@@ -126,7 +126,7 @@ map.data.truncated; // true when more URLs exist than `limit`
126
126
  // Crawl: start a job, then poll it (polling and cancelling are free).
127
127
  const job = await client.extract.crawl(
128
128
  { url: "https://example.com/docs", max_pages: 50, max_depth: 3, format: "markdown" },
129
- { idempotencyKey: "docs-crawl-2026-10-12" }, // optional, sent as Idempotency-Key
129
+ { idempotencyKey: "docs-crawl-2026-10-12" }, // optional; one is generated when omitted
130
130
  );
131
131
  job.data.id; // "crawl_..."
132
132
  job.data.status_url;
@@ -185,16 +185,21 @@ call. Results are kept for 3 days after the job finishes (`expires_at`), up to
185
185
  **`wait: true`.** `crawl()` and `batch()` poll the status endpoint every
186
186
  `pollInterval` ms (default 2,000) until the job is completed, failed or
187
187
  cancelled, then page through every cursor and return
188
- `{ data: { ...summary, results: [all], next_cursor: null } }`. If the job is
188
+ `{ data: { ...summary, results: [all], next_cursor: null }, created: {...} }`,
189
+ where `created` is the 202 job handle (including `webhook_secret`, which is
190
+ only returned on creation), as in the Python SDK (since 0.23.1). If the job is
189
191
  still running after `waitTimeout` ms (default 10 minutes) they throw
190
192
  `ScavioJobTimeoutError`; the job keeps running and the error carries
191
193
  `jobId`, `jobType` and `statusUrl` so you can keep polling or cancel it. For
192
194
  big crawls, prefer a webhook or your own polling loop.
193
195
 
194
- **Retries and idempotency.** The SDK retries 429/5xx and network errors. Pass
195
- `idempotencyKey` when starting a job: repeating a POST with the same key within
196
- 24 hours returns the original job, so a retried request never starts a second
197
- one.
196
+ **Retries and idempotency.** The SDK retries 429/5xx and network errors.
197
+ `crawl()` and `batch()` always send an `Idempotency-Key`: yours when you pass
198
+ `idempotencyKey`, otherwise a random UUID generated for that call and reused on
199
+ every retry of it (since 0.23.1). Repeating a POST with the same key within 24
200
+ hours returns the original job, so a retried start never begins a second,
201
+ billed one. Pass your own key to dedupe across calls or processes. Plain
202
+ `extract()` and `map()` are not jobs and send no key.
198
203
 
199
204
  #### Completion webhooks
200
205
 
@@ -780,13 +785,16 @@ await client.tiktokShop.resolve({ url: "https://vt.tiktok.com/ZT2AHoGsE/" });
780
785
 
781
786
  ### Instagram
782
787
 
783
- Credit cost varies by endpoint, in three tiers:
788
+ 20 endpoints. Typical credit cost per call:
784
789
 
785
790
  | Credits | Methods |
786
791
  |---|---|
787
- | 2 | `userPosts` |
788
- | 8 | `post`, `commentReplies` |
789
- | 10 | `profile`, `userReels`, `userTagged`, `userStories`, `postComments`, `searchUsers`, `searchHashtags`, `userFollowers`, `userFollowings` |
792
+ | 1 | `profile`, `musicPosts` (per page), `userReels`, `userTagged` (2 the first time a username is looked up) |
793
+ | 2 | `userPosts`, `userStories`, `post`, `postComments`, `commentReplies`, `searchUsers`, `searchHashtags`, `userFollowers`, `userFollowings`, `userHighlights`, `highlightStories`, `searchReels`, `searchMusic`, `searchLocations`, `userSimilar`, `postLikers` |
794
+ | 8 | `searchUsers` / `searchHashtags` when a `cursor` is sent |
795
+
796
+ A request can cost up to 10 when it needs extra work; `credits_used` in the
797
+ response is the exact charge.
790
798
 
791
799
  ```typescript
792
800
  // User profile
@@ -797,23 +805,33 @@ await client.instagram.userPosts({ username: "instagram", count: 12 });
797
805
  await client.instagram.userReels({ username: "instagram" });
798
806
  await client.instagram.userTagged({ username: "instagram" });
799
807
 
800
- // User stories
808
+ // User stories, highlights and the stories saved in one highlight
801
809
  await client.instagram.userStories({ username: "instagram" });
810
+ await client.instagram.userHighlights({ username: "natgeo" });
811
+ await client.instagram.highlightStories({ highlight_id: "highlight:18149897764550869" });
802
812
 
803
- // Post detail (by url, media_id, or shortcode)
813
+ // Post detail (by url, media_id, or shortcode) and who liked it
804
814
  await client.instagram.post({ shortcode: "DUajw4YkorV" });
815
+ await client.instagram.postLikers({ shortcode: "DUajw4YkorV" });
805
816
 
806
817
  // Post comments and replies
807
818
  await client.instagram.postComments({ shortcode: "DUajw4YkorV", sort_order: "newest" });
808
819
  await client.instagram.commentReplies({ media_id: "123", comment_id: "456" });
809
820
 
810
- // Search
821
+ // Search users, hashtags, Reels and places
811
822
  await client.instagram.searchUsers({ keyword: "justin" });
812
823
  await client.instagram.searchHashtags({ keyword: "fashion" });
824
+ await client.instagram.searchReels({ keyword: "latte art" });
825
+ await client.instagram.searchLocations({ keyword: "central park" });
826
+
827
+ // Audio: find a track, then the Reels that use it
828
+ await client.instagram.searchMusic({ keyword: "espresso" });
829
+ await client.instagram.musicPosts({ music_id: "1747512212697470" });
813
830
 
814
- // Followers / followings
831
+ // Followers / followings / similar accounts
815
832
  await client.instagram.userFollowers({ username: "instagram", count: 50 });
816
833
  await client.instagram.userFollowings({ username: "instagram" });
834
+ await client.instagram.userSimilar({ username: "mrbeast" });
817
835
  ```
818
836
 
819
837
  ### Threads
package/dist/index.cjs CHANGED
@@ -232,7 +232,7 @@ function parseRetryAfter(header) {
232
232
  var BASE_URL = "https://api.scavio.dev";
233
233
  var DEFAULT_TIMEOUT = 3e4;
234
234
  var DEFAULT_MAX_RETRIES = 2;
235
- var SDK_VERSION = true ? "0.23.0" : "0.0.0";
235
+ var SDK_VERSION = true ? "0.24.0" : "0.0.0";
236
236
  var USER_AGENT = `scavio-js/${SDK_VERSION}`;
237
237
  function isServerRuntime() {
238
238
  const g = globalThis;
@@ -812,42 +812,86 @@ var InstagramNamespace = class {
812
812
  this.client = client;
813
813
  }
814
814
  client;
815
+ /** Get a user profile by username or user_id. 1 credit. */
815
816
  async profile(options) {
816
817
  return this.client._post("/api/v1/instagram/profile", options);
817
818
  }
819
+ /** Get a user's posts, about 12 per page; page with `data.pagination_token`. 2 credits per page. */
818
820
  async userPosts(options) {
819
821
  return this.client._post("/api/v1/instagram/user/posts", options);
820
822
  }
823
+ /** Get a user's Reels. 1 credit (2 the first time a username is looked up). */
821
824
  async userReels(options) {
822
825
  return this.client._post("/api/v1/instagram/user/reels", options);
823
826
  }
827
+ /** Get posts a user is tagged in. 1 credit (2 the first time a username is looked up). */
824
828
  async userTagged(options) {
825
829
  return this.client._post("/api/v1/instagram/user/tagged", options);
826
830
  }
831
+ /** Get a user's active stories. 2 credits. */
827
832
  async userStories(options) {
828
833
  return this.client._post("/api/v1/instagram/user/stories", options);
829
834
  }
835
+ /** Get a single post by url, media_id or shortcode. 2 credits. */
830
836
  async post(options) {
831
837
  return this.client._post("/api/v1/instagram/post", options);
832
838
  }
839
+ /** Get comments on a post; page with `next_min_id`. 2 credits per page. */
833
840
  async postComments(options) {
834
841
  return this.client._post("/api/v1/instagram/post/comments", options);
835
842
  }
843
+ /** Get replies to a comment. 2 credits. */
836
844
  async commentReplies(options) {
837
845
  return this.client._post("/api/v1/instagram/post/comments/replies", options);
838
846
  }
847
+ /** Search users by keyword. 2 credits; 8 when a `cursor` is sent. */
839
848
  async searchUsers(options) {
840
849
  return this.client._post("/api/v1/instagram/search/users", options);
841
850
  }
851
+ /** Search hashtags by keyword. 2 credits; 8 when a `cursor` is sent. */
842
852
  async searchHashtags(options) {
843
853
  return this.client._post("/api/v1/instagram/search/hashtags", options);
844
854
  }
855
+ /** Get a user's followers; page with `next_max_id`. 2 credits per page. */
845
856
  async userFollowers(options) {
846
857
  return this.client._post("/api/v1/instagram/user/followers", options);
847
858
  }
859
+ /** Get the accounts a user follows; page with `next_max_id`. 2 credits per page. */
848
860
  async userFollowings(options) {
849
861
  return this.client._post("/api/v1/instagram/user/followings", options);
850
862
  }
863
+ /** List a user's story highlights (id, title, cover, item count). 2 credits. */
864
+ async userHighlights(options) {
865
+ return this.client._post("/api/v1/instagram/user/highlights", options);
866
+ }
867
+ /** Get every story saved in one highlight, with media URLs. 2 credits. */
868
+ async highlightStories(options) {
869
+ return this.client._post("/api/v1/instagram/highlight/stories", options);
870
+ }
871
+ /** Search Reels by keyword; page with `pagination_token`. 2 credits per page. */
872
+ async searchReels(options) {
873
+ return this.client._post("/api/v1/instagram/search/reels", options);
874
+ }
875
+ /** Search audio tracks by song or artist; returns the id `musicPosts` takes. 2 credits. */
876
+ async searchMusic(options) {
877
+ return this.client._post("/api/v1/instagram/search/music", options);
878
+ }
879
+ /** Get the Reels that use an audio track, plus its total reel count. 1 credit per page. */
880
+ async musicPosts(options) {
881
+ return this.client._post("/api/v1/instagram/music/posts", options);
882
+ }
883
+ /** Search places by name (id, name, address, coordinates). 2 credits. */
884
+ async searchLocations(options) {
885
+ return this.client._post("/api/v1/instagram/search/locations", options);
886
+ }
887
+ /** Get accounts similar to a user. Most creator accounts have them; some brand accounts return none. 2 credits. */
888
+ async userSimilar(options) {
889
+ return this.client._post("/api/v1/instagram/user/similar", options);
890
+ }
891
+ /** Get accounts that liked a post (up to about 1,000) and its total like count. 2 credits. */
892
+ async postLikers(options) {
893
+ return this.client._post("/api/v1/instagram/post/likers", options);
894
+ }
851
895
  };
852
896
 
853
897
  // src/namespaces/walmart.ts
@@ -2999,6 +3043,12 @@ var COLLECT_PAGE_SIZE = 100;
2999
3043
  function sleep2(ms) {
3000
3044
  return new Promise((resolve) => setTimeout(resolve, ms));
3001
3045
  }
3046
+ async function randomUUID() {
3047
+ const g = globalThis;
3048
+ if (typeof g.crypto?.randomUUID === "function") return g.crypto.randomUUID();
3049
+ const nodeCrypto = await import("crypto");
3050
+ return nodeCrypto.randomUUID();
3051
+ }
3002
3052
  var ExtractNamespace = class {
3003
3053
  constructor(client) {
3004
3054
  this.client = client;
@@ -3038,14 +3088,15 @@ var ExtractNamespace = class {
3038
3088
  return this.cancel("batch", id);
3039
3089
  }
3040
3090
  async start(type, body, request2) {
3041
- const headers = request2.idempotencyKey ? { "Idempotency-Key": request2.idempotencyKey } : void 0;
3091
+ const headers = { "Idempotency-Key": request2.idempotencyKey ?? await randomUUID() };
3042
3092
  const created = await this.client._post(
3043
3093
  `/api/v1/extract/${type}`,
3044
3094
  body,
3045
3095
  headers
3046
3096
  );
3047
3097
  if (!request2.wait) return created;
3048
- return this.waitFor(type, created.data.id, created.data.status_url, request2);
3098
+ const done = await this.waitFor(type, created.data.id, created.data.status_url, request2);
3099
+ return { ...done, created: created.data };
3049
3100
  }
3050
3101
  async status(type, id, query = {}) {
3051
3102
  return await this.client._get(`/api/v1/extract/${type}/${encodeURIComponent(id)}`, {