@scavio/ai-sdk 0.3.0 → 0.5.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
@@ -1,8 +1,23 @@
1
1
  # @scavio/ai-sdk
2
2
 
3
- Scavio search tools for the [Vercel AI SDK](https://sdk.vercel.ai). Give any AI SDK agent real-time
4
- search across Google, YouTube, Reddit, Amazon, Walmart, TikTok, and Instagram via the
5
- [Scavio](https://scavio.dev) API.
3
+ Scavio search and page-extraction tools for the [Vercel AI SDK](https://sdk.vercel.ai). Give any AI
4
+ SDK agent real-time search across Google, YouTube, Reddit, Amazon, Walmart, TikTok, and Instagram --
5
+ plus `scavio_extract`, which reads any URL, and opt-in tools that map, crawl or batch-extract whole sites -- via the [Scavio](https://scavio.dev) API.
6
+
7
+ **This package exposes a curated subset of the Scavio API**, chosen for agent
8
+ use: 13 tools by default -- 12 over 7 platforms, plus the core `extract` endpoint, which
9
+ belongs to no platform -- and 5 opt-in website tools (map, crawl, batch) on top. The full surface is 195 endpoints across 31 platforms,
10
+ adding X, LinkedIn, TikTok Shop, eBay, Target, Home Depot, Zillow, Redfin,
11
+ Booking, Airbnb, Tripadvisor, Yelp, Indeed, Glassdoor, the App Store, Google
12
+ Play, SEC, Companies House, G2, Capterra, Google Ads, Meta Ad Library, Threads,
13
+ Kuaishou and the Google verticals (Maps, Shopping, News, Flights, Hotels,
14
+ Trends, AI Mode). To reach all of them, point your agent at the
15
+ [Scavio MCP server](https://scavio.dev/docs/mcp-server) at `mcp.scavio.dev` --
16
+ 191 tools over every endpoint, nothing to vendor.
17
+
18
+ Credits are not uniform: most calls cost 1, YouTube search costs 2 and
19
+ transcript costs 8, Instagram costs 2 to 10 depending on the endpoint, and
20
+ `scavio_extract` is priced by the `mode` you ask for (1 / 1 / 2), not per call.
6
21
 
7
22
  > **Amazon changed (breaking).** The upstream provider moved in 2026-07:
8
23
  > `domain` is replaced by `country`, a two-letter marketplace code (`us`, `gb`
@@ -49,6 +64,7 @@ const res2 = await generateText({
49
64
 
50
65
  | Factory | Tool name | Provider |
51
66
  | --- | --- | --- |
67
+ | `scavioExtract` | `scavio_extract` | Read any URL as Markdown / text / HTML, `/api/v1/extract` (1 credit on `normal` and `advanced`, 2 on `ultra`) |
52
68
  | `scavioSearch` | `scavio_search` | Google web search, `/api/v2/google` (1 credit) |
53
69
  | `scavioYoutubeSearch` | `scavio_youtube_search` | YouTube video search (2 credits) |
54
70
  | `scavioYoutubeVideo` | `scavio_youtube_video` | YouTube video details (1 credit) |
@@ -61,21 +77,100 @@ const res2 = await generateText({
61
77
  | `scavioWalmartSearch` | `scavio_walmart_search` | Walmart products (1 credit) |
62
78
  | `scavioTiktokSearch` | `scavio_tiktok_search` | TikTok videos (1 credit) |
63
79
  | `scavioInstagramSearch` | `scavio_instagram_search` | Instagram users (10 credits) |
64
- | `scavioTools` | all of the above | bundle for `tools:` |
65
-
66
- Each factory accepts `{ apiKey?, maxResults?, ...ScavioConfig }`. The key falls back to `SCAVIO_API_KEY`.
80
+ | `scavioMapWebsite` | `scavio_map_website` | A site's page URLs from its sitemaps and start page, `/api/v1/extract/map` (1 credit on `normal`) |
81
+ | `scavioCrawlWebsite` | `scavio_crawl_website` | Crawl a site from one URL, every page as Markdown / text / HTML (per successful page) |
82
+ | `scavioCrawlStatus` | `scavio_crawl_status` | A crawl's progress and page results, cursor-paged (free) |
83
+ | `scavioBatchExtract` | `scavio_batch_extract` | Extract a list of URLs in one job (per successful page) |
84
+ | `scavioBatchStatus` | `scavio_batch_status` | A batch's progress and page results, cursor-paged (free) |
85
+ | `scavioTools` | all of the above (the five website tools only with `enableCrawl: true`) | bundle for `tools:` |
86
+
87
+ Each factory accepts `{ apiKey?, maxResults?, enableCrawl?, pollIntervalMs?, ...ScavioConfig }`. The key falls back to `SCAVIO_API_KEY`.
67
88
  Get a key at [dashboard.scavio.dev](https://dashboard.scavio.dev) - new accounts get 50 free credits, no
68
89
  credit card.
69
90
 
70
91
  `maxResults` trims the result list in place. Google returns a flat body, so it trims
71
92
  `organic_results`; every other endpoint nests its payload under `data`, so those trim inside `data`
72
93
  (`data.results`, `data.products`, `data.aweme_list`, `data.users`, ...) and the
73
- `{ data, response_time, credits_used, credits_remaining }` envelope is preserved.
94
+ `{ data, response_time, credits_used, credits_remaining }` envelope is preserved. `scavioExtract`
95
+ ignores `maxResults`: it returns page content, not a list, so the page comes back whole.
96
+
97
+ ### Reading a page
98
+
99
+ ```ts
100
+ const page = await generateText({
101
+ model: openai("gpt-5.5"),
102
+ tools: { scavio_extract: scavioExtract() },
103
+ stopWhen: stepCountIs(3),
104
+ prompt: "Summarise the pricing page at https://scavio.dev/pricing",
105
+ });
106
+ ```
107
+
108
+ `scavio_extract` takes `url` plus an optional `format` (`markdown` default, `text`, `html`) and
109
+ `mode`. `mode` is the price-bearing param: `normal` is the standard fetch (1 credit), `advanced`
110
+ renders JavaScript-built pages (1 credit), and `ultra` reaches the hardest pages (2 credits). Only a successful read is billed - a dead link, a bot wall or
111
+ a timeout costs nothing. See [the extract docs](https://scavio.dev/docs/extract).
112
+
113
+ These tools cover the most common surfaces. The full Scavio API - 195 endpoints across 31 platforms
114
+ (Google, YouTube, Amazon, Walmart, Reddit, TikTok, TikTok Shop, Instagram, X, LinkedIn, eBay, Target,
115
+ Home Depot, Zillow, Redfin, Booking, Airbnb, Tripadvisor, Yelp, Indeed, Glassdoor, the App Store,
116
+ Google Play, SEC, Companies House, G2, Capterra, Google Ads, Meta Ad Library, Threads and Kuaishou),
117
+ plus `extract` - is available directly through the
118
+ [`scavio`](https://www.npmjs.com/package/scavio) SDK or the [MCP server](https://scavio.dev/docs).
119
+
120
+ ## Map, crawl and batch
121
+
122
+ Five opt-in tools for whole sites: `scavioTools()` adds them with
123
+ `enableCrawl: true` (off by default, because a crawl bills per page), and each
124
+ factory works on its own:
125
+
126
+ | Tool | What it does | Credits |
127
+ |---|---|---|
128
+ | `scavio_map_website` | List a site's page URLs from its sitemaps and start page, deduplicated and filtered by path or search words | 1 (normal mode; advanced up to 2, ultra up to 10) |
129
+ | `scavio_crawl_website` | Crawl a site from one URL; every same-site page as Markdown, text or HTML | per successful page |
130
+ | `scavio_crawl_status` | A crawl's progress and page results, cursor-paged | free |
131
+ | `scavio_batch_extract` | Extract a list of URLs (up to 1,000, plan-limited) in one job | per successful page |
132
+ | `scavio_batch_status` | A batch's progress and page results, cursor-paged | free |
133
+
134
+ Map answers in one call. Crawl and batch run as background jobs: the start tool
135
+ posts the job and then **waits up to `wait_seconds` (default 45, max 300)** for
136
+ it to finish, returning the job's status with its first page of results (10 by
137
+ default, `limit` up to 100) either way. A job still `queued` or `running` when
138
+ the wait ends keeps going server-side: read the rest later with the matching
139
+ status tool, the returned `data.id` and `next_cursor`. That keeps an agent turn
140
+ bounded while a large crawl (up to 6 hours) runs on.
141
+
142
+ ```ts
143
+ import { scavioTools, scavioCrawlWebsite } from "@scavio/ai-sdk";
144
+
145
+ // All tools plus the five website tools:
146
+ const tools = scavioTools({ enableCrawl: true });
147
+
148
+ // Or just the crawler:
149
+ const res = await generateText({
150
+ model: openai("gpt-5.5"),
151
+ tools: { scavio_crawl_website: scavioCrawlWebsite() },
152
+ stopWhen: stepCountIs(3),
153
+ prompt: "Crawl https://hono.dev/docs (25 pages max) and list its middleware guides",
154
+ });
155
+ // The tool returns { data: { id, status: "completed" | "running", pages, credits_used, results, next_cursor } }.
156
+ ```
157
+
158
+ `pollIntervalMs` (default 3000) sets how often a waiting tool checks its job.
159
+
160
+ **Pricing.** Crawl and batch bill **per successful page** at Extract's price for
161
+ the mode: `normal` (the standard fetch) and `advanced` (renders JavaScript-built
162
+ pages) 1 credit, `ultra` (the hardest pages) 2. Failed and skipped pages are
163
+ free, and if your balance runs out the job stops cleanly with
164
+ `stopped_reason: "insufficient_credits"`. Reading a job is free. Crawl and map
165
+ obey the site's robots.txt, and results are kept for 3 days.
166
+
167
+ **Plan limits** (pages per crawl / active jobs / URLs per batch): Free 10/1/10,
168
+ PAYG 100/1/50, Project 500/2/100, Bootstrap 2,000/3/500, Startup 5,000/5/1,000,
169
+ Growth 10,000/10/1,000.
74
170
 
75
- These tools cover the most common surfaces. The full Scavio API - 98 endpoints across Google,
76
- YouTube, Amazon, Walmart, Reddit, TikTok, TikTok Shop, Instagram, X and LinkedIn - is available
77
- directly through the [`scavio`](https://www.npmjs.com/package/scavio) SDK or the
78
- [MCP server](https://scavio.dev/docs).
171
+ Cancellation, webhooks (signed `Scavio-Signature`) and idempotency keys exist in
172
+ the `scavio` SDK (`extract.cancelCrawl`, `webhook_url`, `idempotencyKey`) and the
173
+ [REST API](https://scavio.dev/docs/extract), but are deliberately not agent tools.
79
174
 
80
175
  ## License
81
176
 
package/dist/index.cjs CHANGED
@@ -22,7 +22,13 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  scavioAmazonOffers: () => scavioAmazonOffers,
24
24
  scavioAmazonSearch: () => scavioAmazonSearch,
25
+ scavioBatchExtract: () => scavioBatchExtract,
26
+ scavioBatchStatus: () => scavioBatchStatus,
27
+ scavioCrawlStatus: () => scavioCrawlStatus,
28
+ scavioCrawlWebsite: () => scavioCrawlWebsite,
29
+ scavioExtract: () => scavioExtract,
25
30
  scavioInstagramSearch: () => scavioInstagramSearch,
31
+ scavioMapWebsite: () => scavioMapWebsite,
26
32
  scavioRedditSearch: () => scavioRedditSearch,
27
33
  scavioSearch: () => scavioSearch,
28
34
  scavioTiktokSearch: () => scavioTiktokSearch,
@@ -57,6 +63,24 @@ function trimData(res, key, max) {
57
63
  }
58
64
  return res;
59
65
  }
66
+ function scavioExtract(config) {
67
+ const c = client(config);
68
+ return (0, import_ai.tool)({
69
+ description: "Read any web page via the Scavio API and get it back as clean Markdown (default), plain text, or raw HTML. Use it on any URL, including one returned by the search tools. Returns `data.content` alongside `data.url`, `data.format`, `data.mode` and `data.content_length`. Cost depends on `mode`: 1 credit on 'normal' and 'advanced', 2 on 'ultra'; a dead link, bot wall or timeout is not billed.",
70
+ inputSchema: import_zod.z.object({
71
+ url: import_zod.z.string().describe(
72
+ "The page to read (1-2048 characters). http(s) only; a bare host is upgraded to https, and loopback, private, link-local and metadata hosts are rejected."
73
+ ),
74
+ format: import_zod.z.enum(["html", "markdown", "text"]).optional().describe(
75
+ "Output format (default 'markdown'): 'markdown' is a readability extraction with page chrome stripped, 'text' is that flattened to plain text, 'html' is the raw page."
76
+ ),
77
+ mode: import_zod.z.enum(["normal", "advanced", "ultra"]).optional().describe(
78
+ "Fetch tier, and the parameter that sets the price: 'normal' (default) is a plain fetch and costs 1 credit, 'advanced' renders JavaScript-built pages and costs 1, 'ultra' reaches the hardest pages and costs 2. Start on 'normal'."
79
+ )
80
+ }),
81
+ execute: async ({ url, format, mode }) => c.extract({ url, format, mode })
82
+ });
83
+ }
60
84
  function scavioSearch(config) {
61
85
  const c = client(config);
62
86
  const max = config?.maxResults ?? 10;
@@ -232,8 +256,133 @@ function scavioInstagramSearch(config) {
232
256
  execute: async ({ keyword }) => trimData(await c.instagram.searchUsers({ keyword }), "users", max)
233
257
  });
234
258
  }
259
+ var JOB_POLL_INTERVAL_MS = 3e3;
260
+ var JOB_WAIT_DEFAULT_SECONDS = 45;
261
+ var JOB_WAIT_MAX_SECONDS = 300;
262
+ var JOB_RESULTS_DEFAULT_LIMIT = 10;
263
+ var JOB_TERMINAL = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
264
+ var sleep = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms));
265
+ async function waitForJob(status, id, waitSeconds, pollMs, query) {
266
+ const deadline = Date.now() + Math.max(0, Math.min(waitSeconds, JOB_WAIT_MAX_SECONDS)) * 1e3;
267
+ for (; ; ) {
268
+ const remaining = deadline - Date.now();
269
+ if (remaining <= 0) break;
270
+ await sleep(Math.min(pollMs, remaining));
271
+ const probe = await status(id, { limit: 1, include_content: false });
272
+ if (JOB_TERMINAL.has(String(probe?.data?.status))) break;
273
+ }
274
+ return await status(id, query);
275
+ }
276
+ async function startAndWait(start, status, input, pollMs) {
277
+ const created = await start();
278
+ const id = created?.data?.id;
279
+ const wait = input.wait_seconds ?? JOB_WAIT_DEFAULT_SECONDS;
280
+ if (!id || wait <= 0) return created;
281
+ const query = { limit: input.limit ?? JOB_RESULTS_DEFAULT_LIMIT };
282
+ if (input.include_content !== void 0) query.include_content = input.include_content;
283
+ return waitForJob(status, id, wait, pollMs, query);
284
+ }
285
+ var MODE_DESCRIPTION = "Fetch tier, and the parameter that sets the price: 'normal' (default) is the standard fetch, 'advanced' renders JavaScript-built pages, 'ultra' reaches the hardest pages.";
286
+ var PATHS_DESCRIPTION = "Path globs (max 20). '*' matches within one path segment, '**' across segments; a pattern without wildcards matches that path and everything under it. Example: ['/blog/**'].";
287
+ var JOB_PRICE = "Billed per SUCCESSFUL page at Extract's price for the mode: 'normal' and 'advanced' 1 credit, 'ultra' 2. Failed and skipped pages are free, and if the balance runs out the job stops cleanly.";
288
+ var jobFields = {
289
+ format: import_zod.z.enum(["html", "markdown", "text"]).optional().describe("Format for each page, as on extract (default 'markdown')."),
290
+ mode: import_zod.z.enum(["normal", "advanced", "ultra"]).optional().describe(MODE_DESCRIPTION),
291
+ wait_seconds: import_zod.z.number().int().min(0).max(JOB_WAIT_MAX_SECONDS).optional().describe("Seconds to wait for the job to finish before returning, 0-300 (default 45). 0 returns the job id at once. A job still running when the wait ends keeps going; read it later with its status tool."),
292
+ limit: import_zod.z.number().int().min(1).max(100).optional().describe("Results per response, 1-100 (default 10, to keep page content inside the context window); page on with next_cursor."),
293
+ include_content: import_zod.z.boolean().optional().describe("Set false to list results without their page content (default true).")
294
+ };
295
+ var jobStatusSchema = import_zod.z.object({
296
+ id: import_zod.z.string().describe("Job id returned when the job was started (data.id)."),
297
+ cursor: import_zod.z.string().optional().describe("next_cursor from the previous response, to read the next page."),
298
+ limit: jobFields.limit,
299
+ status: import_zod.z.enum(["succeeded", "failed", "skipped"]).optional().describe("Only results with this status."),
300
+ include_content: jobFields.include_content
301
+ });
302
+ function scavioMapWebsite(config) {
303
+ const c = client(config);
304
+ return (0, import_ai.tool)({
305
+ description: "List a website's page URLs via the Scavio API, gathered from its sitemaps and its start page, deduplicated, filtered by path or search words and limited: `data.links` [{ url, source, lastmod }], `data.total_found`, `data.truncated`. Pages the site's robots.txt disallows are left out. Use it to find the right pages before extracting or crawling. Costs 1 credit on 'normal'; up to 2 on 'advanced' and up to 10 on 'ultra', priced by what the call needed.",
306
+ inputSchema: import_zod.z.object({
307
+ url: import_zod.z.string().describe("The site to map. A bare host is upgraded to https."),
308
+ search: import_zod.z.string().optional().describe("Only return URLs containing every word of this text (case-insensitive)."),
309
+ limit: import_zod.z.number().int().min(1).max(5e3).optional().describe("Maximum links to return, 1-5000. Default 1000 (or the plan's limit if lower: Free 500, PAYG 1,000, paid plans 5,000)."),
310
+ sitemap: import_zod.z.enum(["include", "only", "skip"]).optional().describe("'include' combines the site's sitemaps with the start page's links (default); 'only' uses sitemaps alone; 'skip' uses page links alone."),
311
+ include_subdomains: import_zod.z.boolean().optional().describe("Also return URLs on subdomains of the site (default false)."),
312
+ include_paths: import_zod.z.array(import_zod.z.string()).optional().describe("Keep only URLs matching these. " + PATHS_DESCRIPTION),
313
+ exclude_paths: import_zod.z.array(import_zod.z.string()).optional().describe("Drop URLs matching these. " + PATHS_DESCRIPTION),
314
+ ignore_query_parameters: import_zod.z.boolean().optional().describe("Treat URLs that differ only by query string as one URL (default true)."),
315
+ mode: jobFields.mode
316
+ }),
317
+ execute: async (input) => await c.extract.map(input)
318
+ });
319
+ }
320
+ function scavioCrawlWebsite(config) {
321
+ const c = client(config);
322
+ const pollMs = config?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS;
323
+ return (0, import_ai.tool)({
324
+ description: "Crawl a website from one start URL via the Scavio API: same-site pages are discovered and extracted breadth-first within the page, depth and path limits, each returned as Markdown, text or HTML. Pages the site's robots.txt disallows are skipped. Waits up to wait_seconds (default 45) and returns `data` { id, status, pages, credits_used, results, next_cursor }; if status is still queued or running, call scavio_crawl_status with the id later. " + JOB_PRICE,
325
+ inputSchema: import_zod.z.object({
326
+ url: import_zod.z.string().describe("Where the crawl starts. Only pages on the same site are crawled."),
327
+ max_pages: import_zod.z.number().int().min(1).max(1e4).optional().describe("Maximum pages to fetch. Default 100. Plan limits: Free 10, PAYG 100, Project 500, Bootstrap 2,000, Startup 5,000, Growth 10,000."),
328
+ max_depth: import_zod.z.number().int().min(0).max(10).optional().describe("How many links away from the start page to follow, 0-10 (default 3). 0 fetches only the start page."),
329
+ include_paths: import_zod.z.array(import_zod.z.string()).optional().describe("Crawl only paths matching these. " + PATHS_DESCRIPTION),
330
+ exclude_paths: import_zod.z.array(import_zod.z.string()).optional().describe("Skip paths matching these. " + PATHS_DESCRIPTION),
331
+ allow_subdomains: import_zod.z.boolean().optional().describe("Also crawl subdomains of the site (default false)."),
332
+ ignore_query_parameters: import_zod.z.boolean().optional().describe("Treat URLs that differ only by query string as one page (default true)."),
333
+ sitemap: import_zod.z.enum(["include", "skip", "only"]).optional().describe("'include' also starts from the site's sitemap (default); 'skip' follows links only; 'only' fetches sitemap pages without following links."),
334
+ ...jobFields
335
+ }),
336
+ execute: async (input) => {
337
+ const { wait_seconds, limit, include_content, ...body } = input;
338
+ return startAndWait(
339
+ () => c.extract.crawl(body),
340
+ (id, q) => c.extract.crawlStatus(id, q),
341
+ { wait_seconds, limit, include_content },
342
+ pollMs
343
+ );
344
+ }
345
+ });
346
+ }
347
+ function scavioCrawlStatus(config) {
348
+ const c = client(config);
349
+ return (0, import_ai.tool)({
350
+ description: "Read a crawl's progress and its page results by job id via the Scavio API, paged by cursor: `data` { status, stopped_reason, pages, credits_used, results: [{ url, status, content }], next_cursor }. Results are kept for 3 days after the crawl finishes. Free: reading a job costs 0 credits.",
351
+ inputSchema: jobStatusSchema,
352
+ execute: async ({ id, limit, ...q }) => await c.extract.crawlStatus(id, { ...q, limit: limit ?? JOB_RESULTS_DEFAULT_LIMIT })
353
+ });
354
+ }
355
+ function scavioBatchExtract(config) {
356
+ const c = client(config);
357
+ const pollMs = config?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS;
358
+ return (0, import_ai.tool)({
359
+ description: "Extract a list of URLs (up to 1,000, plan-limited) in one job via the Scavio API, each returned as Markdown, text or HTML exactly like scavio_extract. Waits up to wait_seconds (default 45) and returns `data` { id, status, pages, credits_used, results, next_cursor }; if status is still queued or running, call scavio_batch_status with the id later. " + JOB_PRICE,
360
+ inputSchema: import_zod.z.object({
361
+ urls: import_zod.z.array(import_zod.z.string()).min(1).max(1e3).describe("The pages to extract (duplicates removed). Plan limits: Free 10, PAYG 50, Project 100, Bootstrap 500, Startup and Growth 1,000."),
362
+ ...jobFields
363
+ }),
364
+ execute: async (input) => {
365
+ const { wait_seconds, limit, include_content, ...body } = input;
366
+ return startAndWait(
367
+ () => c.extract.batch(body),
368
+ (id, q) => c.extract.batchStatus(id, q),
369
+ { wait_seconds, limit, include_content },
370
+ pollMs
371
+ );
372
+ }
373
+ });
374
+ }
375
+ function scavioBatchStatus(config) {
376
+ const c = client(config);
377
+ return (0, import_ai.tool)({
378
+ description: "Read a batch extract's progress and its page results by job id via the Scavio API, paged by cursor: `data` { status, pages, credits_used, results: [{ url, status, content }], next_cursor }. Results are kept for 3 days after the batch finishes. Free: reading a job costs 0 credits.",
379
+ inputSchema: jobStatusSchema,
380
+ execute: async ({ id, limit, ...q }) => await c.extract.batchStatus(id, { ...q, limit: limit ?? JOB_RESULTS_DEFAULT_LIMIT })
381
+ });
382
+ }
235
383
  function scavioTools(config) {
236
384
  return {
385
+ scavio_extract: scavioExtract(config),
237
386
  scavio_search: scavioSearch(config),
238
387
  scavio_youtube_search: scavioYoutubeSearch(config),
239
388
  scavio_youtube_video: scavioYoutubeVideo(config),
@@ -245,14 +394,27 @@ function scavioTools(config) {
245
394
  scavio_amazon_offers: scavioAmazonOffers(config),
246
395
  scavio_walmart_search: scavioWalmartSearch(config),
247
396
  scavio_tiktok_search: scavioTiktokSearch(config),
248
- scavio_instagram_search: scavioInstagramSearch(config)
397
+ scavio_instagram_search: scavioInstagramSearch(config),
398
+ ...config?.enableCrawl ? {
399
+ scavio_map_website: scavioMapWebsite(config),
400
+ scavio_crawl_website: scavioCrawlWebsite(config),
401
+ scavio_crawl_status: scavioCrawlStatus(config),
402
+ scavio_batch_extract: scavioBatchExtract(config),
403
+ scavio_batch_status: scavioBatchStatus(config)
404
+ } : {}
249
405
  };
250
406
  }
251
407
  // Annotate the CommonJS export names for ESM import in node:
252
408
  0 && (module.exports = {
253
409
  scavioAmazonOffers,
254
410
  scavioAmazonSearch,
411
+ scavioBatchExtract,
412
+ scavioBatchStatus,
413
+ scavioCrawlStatus,
414
+ scavioCrawlWebsite,
415
+ scavioExtract,
255
416
  scavioInstagramSearch,
417
+ scavioMapWebsite,
256
418
  scavioRedditSearch,
257
419
  scavioSearch,
258
420
  scavioTiktokSearch,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport { Scavio, type ScavioConfig, type GoogleSearchOptions } from \"scavio\";\n\nexport interface ScavioToolConfig extends ScavioConfig {\n /**\n * Max number of items to keep in the tool's result list. Defaults to 10.\n * Trimmed inside `data` on every platform except Google, whose body is flat.\n */\n maxResults?: number;\n}\n\nfunction client(config?: ScavioToolConfig): Scavio {\n return new Scavio({ apiKey: config?.apiKey });\n}\n\n/**\n * Google is the ONLY family with a flat body: `organic_results` and friends sit\n * at the top level, next to `response_time` / `credits_used` / `credits_remaining`.\n */\nfunction trimFlat(res: Record<string, unknown>, key: string, max: number): Record<string, unknown> {\n const list = res[key];\n if (Array.isArray(list) && list.length > max) {\n return { ...res, [key]: list.slice(0, max) };\n }\n return res;\n}\n\n/**\n * Every non-Google endpoint nests its payload under `data` - the response is\n * `{ data: { products: [...] }, response_time, credits_used, credits_remaining }`.\n * Trimming the top level is therefore a silent no-op, so those tools trim\n * inside `data`.\n */\nfunction trimData(res: Record<string, unknown>, key: string, max: number): Record<string, unknown> {\n const data = res.data;\n if (!data || typeof data !== \"object\") return res;\n const list = (data as Record<string, unknown>)[key];\n if (Array.isArray(list) && list.length > max) {\n return { ...res, data: { ...(data as Record<string, unknown>), [key]: list.slice(0, max) } };\n }\n return res;\n}\n\n/** Google web search (/api/v2/google, 1 credit). */\nexport function scavioSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search the web with Google via the Scavio API (1 credit). Returns real-time organic search results, each with a title, link, and snippet, under `organic_results`.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n countryCode: z.string().optional().describe('Two-letter country code to localize results, e.g. \"us\".'),\n language: z.string().optional().describe('Two-letter UI language code, e.g. \"en\".'),\n page: z.number().int().optional().describe(\"1-based result page; page 2 starts at result 10.\"),\n device: z.enum([\"desktop\", \"mobile\"]).optional().describe(\"Device to emulate.\"),\n nfpr: z.boolean().optional().describe(\"Disable spelling auto-correction / similar-result substitution when true.\"),\n }),\n execute: async ({ query, countryCode, language, page, device, nfpr }) => {\n const params: GoogleSearchOptions = { query };\n if (countryCode) params.gl = countryCode;\n if (language) params.hl = language;\n if (page && page > 1) params.start = (page - 1) * 10;\n if (device) params.device = device;\n if (nfpr !== undefined) params.nfpr = nfpr;\n return trimFlat(await c.google.search(params), \"organic_results\", max);\n },\n });\n}\n\n/** YouTube video search (2 credits). */\nexport function scavioYoutubeSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search YouTube for videos, channels, or playlists via the Scavio API (2 credits). Videos come back under `data.results`, with `data.channels` and `data.playlists` alongside.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n upload_date: z.string().optional().describe(\"Upload date filter, e.g. 'today', 'this_week', 'this_month'.\"),\n type: z.string().optional().describe(\"Result type: 'video', 'channel', 'playlist', 'movie'.\"),\n duration: z.string().optional().describe(\"Duration filter: 'short', 'medium', 'long'.\"),\n sort_by: z.string().optional().describe(\"Sort order: 'relevance', 'date', 'view_count', 'rating'.\"),\n cursor: z.string().optional().describe(\"Pagination cursor (`next_cursor`) from a prior response.\"),\n }),\n execute: async ({ query, upload_date, type, duration, sort_by, cursor }) =>\n trimData(\n await c.youtube.search({ query, upload_date, type, duration, sort_by, cursor } as Parameters<\n typeof c.youtube.search\n >[0]),\n \"results\",\n max,\n ),\n });\n}\n\n/** YouTube video details (1 credit). */\nexport function scavioYoutubeVideo(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch full details for a YouTube video (title, author, view count, description, captions, chapters) via the Scavio API.\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n }),\n execute: async ({ video_id }) => c.youtube.video({ video_id }),\n });\n}\n\n/** YouTube video transcript / subtitles (8 credits). */\nexport function scavioYoutubeTranscript(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch a YouTube video's transcript or timed subtitles via the Scavio API (8 credits).\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n language: z.string().optional().describe(\"Transcript language code (default 'en').\"),\n format: z.enum([\"text\", \"srt\"]).optional().describe(\"'text' for a plain transcript, 'srt' for timed subtitles.\"),\n }),\n execute: async ({ video_id, language, format }) =>\n c.youtube.transcript({ video_id, language, format } as Parameters<typeof c.youtube.transcript>[0]),\n });\n}\n\n/** YouTube video comments (1 credit). */\nexport function scavioYoutubeComments(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description: \"List comments on a YouTube video via the Scavio API.\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n cursor: z.string().optional().describe(\"Pagination cursor.\"),\n }),\n execute: async ({ video_id, cursor }) =>\n trimData(\n await c.youtube.comments({ video_id, cursor } as Parameters<typeof c.youtube.comments>[0]),\n \"comments\",\n max,\n ),\n });\n}\n\n/** YouTube channel details (1 credit). */\nexport function scavioYoutubeChannel(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch a YouTube channel's details (subscribers, video count, views, links) via the Scavio API.\",\n inputSchema: z.object({\n channel_id: z.string().describe(\"YouTube channel id, @handle, or channel URL.\"),\n }),\n execute: async ({ channel_id }) => c.youtube.channel({ channel_id }),\n });\n}\n\n/**\n * Reddit post search (1 credit).\n *\n * The endpoint takes `query` and `cursor` and nothing else - it cannot sort or\n * filter by type, so no such input is offered. The API silently ignores those\n * params, which would leave a model believing it had filtered when it had not.\n */\nexport function scavioRedditSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Reddit posts via the Scavio API (1 credit). Returns matching posts under `data.results` with `data.next_cursor` for the next page. Results cannot be sorted or filtered by type.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n cursor: z.string().optional().describe(\"Pagination cursor (`next_cursor`) from a prior response.\"),\n }),\n execute: async ({ query, cursor }) => trimData(await c.reddit.search({ query, cursor }), \"results\", max),\n });\n}\n\n/**\n * Amazon product search.\n *\n * `domain` was dropped in favour of `country`, a two-letter marketplace code -\n * the upstream provider changed in 2026-07 and no longer takes a domain\n * suffix. It still works on the wire as a deprecated alias, but a model should\n * only ever see one spelling of a param.\n */\nexport function scavioAmazonSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Amazon for products via the Scavio API. Results are unsorted and cannot be filtered by category, merchant or price.\",\n inputSchema: z.object({\n query: z.string().describe(\"The product search query.\"),\n country: z\n .string()\n .optional()\n .describe(\n \"Marketplace country code (ISO 3166-1 alpha-2), not a domain: us (default), gb (the UK is gb, not uk), de, fr, jp, ... An unknown code falls back to us.\"\n ),\n }),\n execute: async ({ query, country }) =>\n trimData(await c.amazon.search({ query, country }), \"products\", max),\n });\n}\n\n/** Every seller offer for one Amazon ASIN. */\nexport function scavioAmazonOffers(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"List every seller offer for one Amazon ASIN via the Scavio API: price, seller, condition, shipping, and which offer holds the buy box. Page 1 only.\",\n inputSchema: z.object({\n asin: z.string().describe(\"Amazon Standard Identification Number (ASIN) of the product.\"),\n country: z\n .string()\n .optional()\n .describe(\n \"Marketplace country code (ISO 3166-1 alpha-2), not a domain: us (default), gb (the UK is gb, not uk), de, fr, jp, ... An unknown code falls back to us.\"\n ),\n }),\n execute: async ({ asin, country }) =>\n trimData(await c.amazon.offers({ asin, country }), \"offers\", max),\n });\n}\n\n/** Walmart product search. */\nexport function scavioWalmartSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description: \"Search Walmart for products via the Scavio API. Products come back under `data.products`.\",\n inputSchema: z.object({\n query: z.string().describe(\"The product search query.\"),\n }),\n execute: async ({ query }) => trimData(await c.walmart.search({ query }), \"products\", max),\n });\n}\n\n/** TikTok video search. */\nexport function scavioTiktokSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search TikTok for videos by keyword via the Scavio API. Videos come back under `data.aweme_list`.\",\n inputSchema: z.object({\n keyword: z.string().describe(\"The search keyword.\"),\n sort_type: z.enum([\"0\", \"1\"]).optional().describe(\"Sort order: '0' relevance, '1' most likes.\"),\n publish_time: z\n .enum([\"0\", \"1\", \"7\", \"30\", \"90\", \"180\"])\n .optional()\n .describe(\"Publish window in days: '0' all time, '1', '7', '30', '90', '180'.\"),\n }),\n execute: async ({ keyword, sort_type, publish_time }) =>\n trimData(\n await c.tiktok.searchVideos({\n keyword,\n sort_type,\n publish_time,\n } as Parameters<typeof c.tiktok.searchVideos>[0]),\n \"aweme_list\",\n max,\n ),\n });\n}\n\n/** Instagram user search. */\nexport function scavioInstagramSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Instagram for users by keyword via the Scavio API (10 credits). Users come back under `data.users`.\",\n inputSchema: z.object({\n keyword: z.string().describe(\"The search keyword.\"),\n }),\n execute: async ({ keyword }) => trimData(await c.instagram.searchUsers({ keyword }), \"users\", max),\n });\n}\n\n/**\n * All Scavio tools as an object keyed by tool name, ready to spread into the\n * `tools` option of `generateText` / `streamText`.\n */\nexport function scavioTools(config?: ScavioToolConfig) {\n return {\n scavio_search: scavioSearch(config),\n scavio_youtube_search: scavioYoutubeSearch(config),\n scavio_youtube_video: scavioYoutubeVideo(config),\n scavio_youtube_transcript: scavioYoutubeTranscript(config),\n scavio_youtube_comments: scavioYoutubeComments(config),\n scavio_youtube_channel: scavioYoutubeChannel(config),\n scavio_reddit_search: scavioRedditSearch(config),\n scavio_amazon_search: scavioAmazonSearch(config),\n scavio_amazon_offers: scavioAmazonOffers(config),\n scavio_walmart_search: scavioWalmartSearch(config),\n scavio_tiktok_search: scavioTiktokSearch(config),\n scavio_instagram_search: scavioInstagramSearch(config),\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport { Scavio, type ScavioConfig, type GoogleSearchOptions } from \"scavio\";\n\nexport interface ScavioToolConfig extends ScavioConfig {\n /**\n * Max number of items to keep in the tool's result list. Defaults to 10.\n * Trimmed inside `data` on every platform except Google, whose body is flat.\n * Ignored by `scavioExtract`, which returns page content rather than a list.\n */\n maxResults?: number;\n /**\n * Add the five website tools (map, crawl, crawl status, batch extract, batch\n * status) to `scavioTools()`. Off by default: a crawl bills per page. The\n * individual factories (`scavioCrawlWebsite` and friends) work regardless.\n */\n enableCrawl?: boolean;\n /** Milliseconds between progress polls while a crawl or batch tool waits. Default 3000. */\n pollIntervalMs?: number;\n}\n\nfunction client(config?: ScavioToolConfig): Scavio {\n return new Scavio({ apiKey: config?.apiKey });\n}\n\n/**\n * Google is the ONLY family with a flat body: `organic_results` and friends sit\n * at the top level, next to `response_time` / `credits_used` / `credits_remaining`.\n */\nfunction trimFlat(res: Record<string, unknown>, key: string, max: number): Record<string, unknown> {\n const list = res[key];\n if (Array.isArray(list) && list.length > max) {\n return { ...res, [key]: list.slice(0, max) };\n }\n return res;\n}\n\n/**\n * Every non-Google endpoint nests its payload under `data` - the response is\n * `{ data: { products: [...] }, response_time, credits_used, credits_remaining }`.\n * Trimming the top level is therefore a silent no-op, so those tools trim\n * inside `data`.\n */\nfunction trimData(res: Record<string, unknown>, key: string, max: number): Record<string, unknown> {\n const data = res.data;\n if (!data || typeof data !== \"object\") return res;\n const list = (data as Record<string, unknown>)[key];\n if (Array.isArray(list) && list.length > max) {\n return { ...res, data: { ...(data as Record<string, unknown>), [key]: list.slice(0, max) } };\n }\n return res;\n}\n\n/**\n * Read any URL (/api/v1/extract).\n *\n * The one tool here that is not tied to a platform, and the only one `maxResults`\n * does not touch: extract returns page CONTENT, not a result list, so there is\n * nothing to trim and the body is returned whole. `extract` is a TOP-LEVEL\n * method on the SDK client - `c.extract({ url })`, never `c.extract.extract()`.\n *\n * Credits are a function of `mode`, not a per-call constant: \"normal\" 1,\n * \"advanced\" 1, \"ultra\" 2. Only a successful read is billed.\n */\nexport function scavioExtract(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Read any web page via the Scavio API and get it back as clean Markdown (default), plain text, or raw HTML. Use it on any URL, including one returned by the search tools. Returns `data.content` alongside `data.url`, `data.format`, `data.mode` and `data.content_length`. Cost depends on `mode`: 1 credit on 'normal' and 'advanced', 2 on 'ultra'; a dead link, bot wall or timeout is not billed.\",\n inputSchema: z.object({\n url: z\n .string()\n .describe(\n \"The page to read (1-2048 characters). http(s) only; a bare host is upgraded to https, and loopback, private, link-local and metadata hosts are rejected.\",\n ),\n format: z\n .enum([\"html\", \"markdown\", \"text\"])\n .optional()\n .describe(\n \"Output format (default 'markdown'): 'markdown' is a readability extraction with page chrome stripped, 'text' is that flattened to plain text, 'html' is the raw page.\",\n ),\n mode: z\n .enum([\"normal\", \"advanced\", \"ultra\"])\n .optional()\n .describe(\n \"Fetch tier, and the parameter that sets the price: 'normal' (default) is a plain fetch and costs 1 credit, 'advanced' renders JavaScript-built pages and costs 1, 'ultra' reaches the hardest pages and costs 2. Start on 'normal'.\",\n ),\n }),\n execute: async ({ url, format, mode }) => c.extract({ url, format, mode }),\n });\n}\n\n/** Google web search (/api/v2/google, 1 credit). */\nexport function scavioSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search the web with Google via the Scavio API (1 credit). Returns real-time organic search results, each with a title, link, and snippet, under `organic_results`.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n countryCode: z.string().optional().describe('Two-letter country code to localize results, e.g. \"us\".'),\n language: z.string().optional().describe('Two-letter UI language code, e.g. \"en\".'),\n page: z.number().int().optional().describe(\"1-based result page; page 2 starts at result 10.\"),\n device: z.enum([\"desktop\", \"mobile\"]).optional().describe(\"Device to emulate.\"),\n nfpr: z.boolean().optional().describe(\"Disable spelling auto-correction / similar-result substitution when true.\"),\n }),\n execute: async ({ query, countryCode, language, page, device, nfpr }) => {\n const params: GoogleSearchOptions = { query };\n if (countryCode) params.gl = countryCode;\n if (language) params.hl = language;\n if (page && page > 1) params.start = (page - 1) * 10;\n if (device) params.device = device;\n if (nfpr !== undefined) params.nfpr = nfpr;\n return trimFlat(await c.google.search(params), \"organic_results\", max);\n },\n });\n}\n\n/** YouTube video search (2 credits). */\nexport function scavioYoutubeSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search YouTube for videos, channels, or playlists via the Scavio API (2 credits). Videos come back under `data.results`, with `data.channels` and `data.playlists` alongside.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n upload_date: z.string().optional().describe(\"Upload date filter, e.g. 'today', 'this_week', 'this_month'.\"),\n type: z.string().optional().describe(\"Result type: 'video', 'channel', 'playlist', 'movie'.\"),\n duration: z.string().optional().describe(\"Duration filter: 'short', 'medium', 'long'.\"),\n sort_by: z.string().optional().describe(\"Sort order: 'relevance', 'date', 'view_count', 'rating'.\"),\n cursor: z.string().optional().describe(\"Pagination cursor (`next_cursor`) from a prior response.\"),\n }),\n execute: async ({ query, upload_date, type, duration, sort_by, cursor }) =>\n trimData(\n await c.youtube.search({ query, upload_date, type, duration, sort_by, cursor } as Parameters<\n typeof c.youtube.search\n >[0]),\n \"results\",\n max,\n ),\n });\n}\n\n/** YouTube video details (1 credit). */\nexport function scavioYoutubeVideo(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch full details for a YouTube video (title, author, view count, description, captions, chapters) via the Scavio API.\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n }),\n execute: async ({ video_id }) => c.youtube.video({ video_id }),\n });\n}\n\n/** YouTube video transcript / subtitles (8 credits). */\nexport function scavioYoutubeTranscript(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch a YouTube video's transcript or timed subtitles via the Scavio API (8 credits).\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n language: z.string().optional().describe(\"Transcript language code (default 'en').\"),\n format: z.enum([\"text\", \"srt\"]).optional().describe(\"'text' for a plain transcript, 'srt' for timed subtitles.\"),\n }),\n execute: async ({ video_id, language, format }) =>\n c.youtube.transcript({ video_id, language, format } as Parameters<typeof c.youtube.transcript>[0]),\n });\n}\n\n/** YouTube video comments (1 credit). */\nexport function scavioYoutubeComments(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description: \"List comments on a YouTube video via the Scavio API.\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n cursor: z.string().optional().describe(\"Pagination cursor.\"),\n }),\n execute: async ({ video_id, cursor }) =>\n trimData(\n await c.youtube.comments({ video_id, cursor } as Parameters<typeof c.youtube.comments>[0]),\n \"comments\",\n max,\n ),\n });\n}\n\n/** YouTube channel details (1 credit). */\nexport function scavioYoutubeChannel(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch a YouTube channel's details (subscribers, video count, views, links) via the Scavio API.\",\n inputSchema: z.object({\n channel_id: z.string().describe(\"YouTube channel id, @handle, or channel URL.\"),\n }),\n execute: async ({ channel_id }) => c.youtube.channel({ channel_id }),\n });\n}\n\n/**\n * Reddit post search (1 credit).\n *\n * The endpoint takes `query` and `cursor` and nothing else - it cannot sort or\n * filter by type, so no such input is offered. The API silently ignores those\n * params, which would leave a model believing it had filtered when it had not.\n */\nexport function scavioRedditSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Reddit posts via the Scavio API (1 credit). Returns matching posts under `data.results` with `data.next_cursor` for the next page. Results cannot be sorted or filtered by type.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n cursor: z.string().optional().describe(\"Pagination cursor (`next_cursor`) from a prior response.\"),\n }),\n execute: async ({ query, cursor }) => trimData(await c.reddit.search({ query, cursor }), \"results\", max),\n });\n}\n\n/**\n * Amazon product search.\n *\n * `domain` was dropped in favour of `country`, a two-letter marketplace code -\n * the upstream provider changed in 2026-07 and no longer takes a domain\n * suffix. It still works on the wire as a deprecated alias, but a model should\n * only ever see one spelling of a param.\n */\nexport function scavioAmazonSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Amazon for products via the Scavio API. Results are unsorted and cannot be filtered by category, merchant or price.\",\n inputSchema: z.object({\n query: z.string().describe(\"The product search query.\"),\n country: z\n .string()\n .optional()\n .describe(\n \"Marketplace country code (ISO 3166-1 alpha-2), not a domain: us (default), gb (the UK is gb, not uk), de, fr, jp, ... An unknown code falls back to us.\"\n ),\n }),\n execute: async ({ query, country }) =>\n trimData(await c.amazon.search({ query, country }), \"products\", max),\n });\n}\n\n/** Every seller offer for one Amazon ASIN. */\nexport function scavioAmazonOffers(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"List every seller offer for one Amazon ASIN via the Scavio API: price, seller, condition, shipping, and which offer holds the buy box. Page 1 only.\",\n inputSchema: z.object({\n asin: z.string().describe(\"Amazon Standard Identification Number (ASIN) of the product.\"),\n country: z\n .string()\n .optional()\n .describe(\n \"Marketplace country code (ISO 3166-1 alpha-2), not a domain: us (default), gb (the UK is gb, not uk), de, fr, jp, ... An unknown code falls back to us.\"\n ),\n }),\n execute: async ({ asin, country }) =>\n trimData(await c.amazon.offers({ asin, country }), \"offers\", max),\n });\n}\n\n/** Walmart product search. */\nexport function scavioWalmartSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description: \"Search Walmart for products via the Scavio API. Products come back under `data.products`.\",\n inputSchema: z.object({\n query: z.string().describe(\"The product search query.\"),\n }),\n execute: async ({ query }) => trimData(await c.walmart.search({ query }), \"products\", max),\n });\n}\n\n/** TikTok video search. */\nexport function scavioTiktokSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search TikTok for videos by keyword via the Scavio API. Videos come back under `data.aweme_list`.\",\n inputSchema: z.object({\n keyword: z.string().describe(\"The search keyword.\"),\n sort_type: z.enum([\"0\", \"1\"]).optional().describe(\"Sort order: '0' relevance, '1' most likes.\"),\n publish_time: z\n .enum([\"0\", \"1\", \"7\", \"30\", \"90\", \"180\"])\n .optional()\n .describe(\"Publish window in days: '0' all time, '1', '7', '30', '90', '180'.\"),\n }),\n execute: async ({ keyword, sort_type, publish_time }) =>\n trimData(\n await c.tiktok.searchVideos({\n keyword,\n sort_type,\n publish_time,\n } as Parameters<typeof c.tiktok.searchVideos>[0]),\n \"aweme_list\",\n max,\n ),\n });\n}\n\n/** Instagram user search. */\nexport function scavioInstagramSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Instagram for users by keyword via the Scavio API (10 credits). Users come back under `data.users`.\",\n inputSchema: z.object({\n keyword: z.string().describe(\"The search keyword.\"),\n }),\n execute: async ({ keyword }) => trimData(await c.instagram.searchUsers({ keyword }), \"users\", max),\n });\n}\n\n// ---------------------------------------------------------------------------\n// Website map, crawl and batch: the multi-page members of the Extract family.\n//\n// Map answers in one call. Crawl and batch are background jobs: the start tools\n// post the job, then wait up to wait_seconds (default 45, max 300) for it to\n// finish, polling progress without page content, and return the job's status\n// with its first page of results either way. A job still running when the wait\n// ends keeps going server-side; read the rest with the matching status tool.\n// ---------------------------------------------------------------------------\n\nconst JOB_POLL_INTERVAL_MS = 3_000;\nconst JOB_WAIT_DEFAULT_SECONDS = 45;\nconst JOB_WAIT_MAX_SECONDS = 300;\nconst JOB_RESULTS_DEFAULT_LIMIT = 10;\nconst JOB_TERMINAL = new Set([\"completed\", \"failed\", \"cancelled\"]);\n\ntype JobQuery = {\n cursor?: string;\n limit?: number;\n status?: \"succeeded\" | \"failed\" | \"skipped\";\n include_content?: boolean;\n};\ntype JobPayload = { data?: { id?: string; status?: string } } & Record<string, unknown>;\ntype JobStatusFn = (id: string, query: JobQuery) => Promise<unknown>;\n\n// lib is ES2022 only (no DOM or Node types); every runtime this targets has setTimeout.\ndeclare const setTimeout: (callback: () => void, ms: number) => unknown;\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(() => resolve(), ms));\n\n/** Poll a job (content-free) until it finishes or the wait runs out, then read one results page. */\nasync function waitForJob(\n status: JobStatusFn,\n id: string,\n waitSeconds: number,\n pollMs: number,\n query: JobQuery,\n): Promise<Record<string, unknown>> {\n const deadline = Date.now() + Math.max(0, Math.min(waitSeconds, JOB_WAIT_MAX_SECONDS)) * 1000;\n for (;;) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n await sleep(Math.min(pollMs, remaining));\n const probe = (await status(id, { limit: 1, include_content: false })) as JobPayload;\n if (JOB_TERMINAL.has(String(probe?.data?.status))) break;\n }\n return (await status(id, query)) as Record<string, unknown>;\n}\n\n/** Start a job, then wait for it (bounded). wait_seconds 0 returns the 202 payload. */\nasync function startAndWait(\n start: () => Promise<unknown>,\n status: JobStatusFn,\n input: { wait_seconds?: number; limit?: number; include_content?: boolean },\n pollMs: number,\n): Promise<Record<string, unknown>> {\n const created = (await start()) as JobPayload;\n const id = created?.data?.id;\n const wait = input.wait_seconds ?? JOB_WAIT_DEFAULT_SECONDS;\n if (!id || wait <= 0) return created;\n const query: JobQuery = { limit: input.limit ?? JOB_RESULTS_DEFAULT_LIMIT };\n if (input.include_content !== undefined) query.include_content = input.include_content;\n return waitForJob(status, id, wait, pollMs, query);\n}\n\nconst MODE_DESCRIPTION =\n \"Fetch tier, and the parameter that sets the price: 'normal' (default) is the standard fetch, 'advanced' renders JavaScript-built pages, 'ultra' reaches the hardest pages.\";\nconst PATHS_DESCRIPTION =\n \"Path globs (max 20). '*' matches within one path segment, '**' across segments; a pattern without wildcards matches that path and everything under it. Example: ['/blog/**'].\";\nconst JOB_PRICE =\n \"Billed per SUCCESSFUL page at Extract's price for the mode: 'normal' and 'advanced' 1 credit, 'ultra' 2. Failed and skipped pages are free, and if the balance runs out the job stops cleanly.\";\n\nconst jobFields = {\n format: z.enum([\"html\", \"markdown\", \"text\"]).optional().describe(\"Format for each page, as on extract (default 'markdown').\"),\n mode: z.enum([\"normal\", \"advanced\", \"ultra\"]).optional().describe(MODE_DESCRIPTION),\n wait_seconds: z\n .number()\n .int()\n .min(0)\n .max(JOB_WAIT_MAX_SECONDS)\n .optional()\n .describe(\"Seconds to wait for the job to finish before returning, 0-300 (default 45). 0 returns the job id at once. A job still running when the wait ends keeps going; read it later with its status tool.\"),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\"Results per response, 1-100 (default 10, to keep page content inside the context window); page on with next_cursor.\"),\n include_content: z.boolean().optional().describe(\"Set false to list results without their page content (default true).\"),\n};\n\nconst jobStatusSchema = z.object({\n id: z.string().describe(\"Job id returned when the job was started (data.id).\"),\n cursor: z.string().optional().describe(\"next_cursor from the previous response, to read the next page.\"),\n limit: jobFields.limit,\n status: z.enum([\"succeeded\", \"failed\", \"skipped\"]).optional().describe(\"Only results with this status.\"),\n include_content: jobFields.include_content,\n});\n\n/** Map a website's URLs (/api/v1/extract/map). 1 credit on 'normal'. */\nexport function scavioMapWebsite(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"List a website's page URLs via the Scavio API, gathered from its sitemaps and its start page, deduplicated, filtered by path or search words and limited: `data.links` [{ url, source, lastmod }], `data.total_found`, `data.truncated`. Pages the site's robots.txt disallows are left out. Use it to find the right pages before extracting or crawling. Costs 1 credit on 'normal'; up to 2 on 'advanced' and up to 10 on 'ultra', priced by what the call needed.\",\n inputSchema: z.object({\n url: z.string().describe(\"The site to map. A bare host is upgraded to https.\"),\n search: z.string().optional().describe(\"Only return URLs containing every word of this text (case-insensitive).\"),\n limit: z.number().int().min(1).max(5000).optional().describe(\"Maximum links to return, 1-5000. Default 1000 (or the plan's limit if lower: Free 500, PAYG 1,000, paid plans 5,000).\"),\n sitemap: z.enum([\"include\", \"only\", \"skip\"]).optional().describe(\"'include' combines the site's sitemaps with the start page's links (default); 'only' uses sitemaps alone; 'skip' uses page links alone.\"),\n include_subdomains: z.boolean().optional().describe(\"Also return URLs on subdomains of the site (default false).\"),\n include_paths: z.array(z.string()).optional().describe(\"Keep only URLs matching these. \" + PATHS_DESCRIPTION),\n exclude_paths: z.array(z.string()).optional().describe(\"Drop URLs matching these. \" + PATHS_DESCRIPTION),\n ignore_query_parameters: z.boolean().optional().describe(\"Treat URLs that differ only by query string as one URL (default true).\"),\n mode: jobFields.mode,\n }),\n execute: async (input) =>\n (await c.extract.map(input as Parameters<typeof c.extract.map>[0])) as unknown as Record<string, unknown>,\n });\n}\n\n/** Crawl a website (/api/v1/extract/crawl), then wait (bounded) for it. */\nexport function scavioCrawlWebsite(config?: ScavioToolConfig) {\n const c = client(config);\n const pollMs = config?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS;\n return tool({\n description:\n \"Crawl a website from one start URL via the Scavio API: same-site pages are discovered and extracted breadth-first within the page, depth and path limits, each returned as Markdown, text or HTML. Pages the site's robots.txt disallows are skipped. Waits up to wait_seconds (default 45) and returns `data` { id, status, pages, credits_used, results, next_cursor }; if status is still queued or running, call scavio_crawl_status with the id later. \" +\n JOB_PRICE,\n inputSchema: z.object({\n url: z.string().describe(\"Where the crawl starts. Only pages on the same site are crawled.\"),\n max_pages: z.number().int().min(1).max(10000).optional().describe(\"Maximum pages to fetch. Default 100. Plan limits: Free 10, PAYG 100, Project 500, Bootstrap 2,000, Startup 5,000, Growth 10,000.\"),\n max_depth: z.number().int().min(0).max(10).optional().describe(\"How many links away from the start page to follow, 0-10 (default 3). 0 fetches only the start page.\"),\n include_paths: z.array(z.string()).optional().describe(\"Crawl only paths matching these. \" + PATHS_DESCRIPTION),\n exclude_paths: z.array(z.string()).optional().describe(\"Skip paths matching these. \" + PATHS_DESCRIPTION),\n allow_subdomains: z.boolean().optional().describe(\"Also crawl subdomains of the site (default false).\"),\n ignore_query_parameters: z.boolean().optional().describe(\"Treat URLs that differ only by query string as one page (default true).\"),\n sitemap: z.enum([\"include\", \"skip\", \"only\"]).optional().describe(\"'include' also starts from the site's sitemap (default); 'skip' follows links only; 'only' fetches sitemap pages without following links.\"),\n ...jobFields,\n }),\n execute: async (input) => {\n const { wait_seconds, limit, include_content, ...body } = input;\n return startAndWait(\n () => c.extract.crawl(body as Parameters<typeof c.extract.crawl>[0]),\n (id, q) => c.extract.crawlStatus(id, q),\n { wait_seconds, limit, include_content },\n pollMs,\n );\n },\n });\n}\n\n/** A crawl's progress and page results (GET /api/v1/extract/crawl/{id}). Free. */\nexport function scavioCrawlStatus(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Read a crawl's progress and its page results by job id via the Scavio API, paged by cursor: `data` { status, stopped_reason, pages, credits_used, results: [{ url, status, content }], next_cursor }. Results are kept for 3 days after the crawl finishes. Free: reading a job costs 0 credits.\",\n inputSchema: jobStatusSchema,\n execute: async ({ id, limit, ...q }) =>\n (await c.extract.crawlStatus(id, { ...q, limit: limit ?? JOB_RESULTS_DEFAULT_LIMIT })) as unknown as Record<string, unknown>,\n });\n}\n\n/** Extract a list of URLs in one job (/api/v1/extract/batch), then wait (bounded). */\nexport function scavioBatchExtract(config?: ScavioToolConfig) {\n const c = client(config);\n const pollMs = config?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS;\n return tool({\n description:\n \"Extract a list of URLs (up to 1,000, plan-limited) in one job via the Scavio API, each returned as Markdown, text or HTML exactly like scavio_extract. Waits up to wait_seconds (default 45) and returns `data` { id, status, pages, credits_used, results, next_cursor }; if status is still queued or running, call scavio_batch_status with the id later. \" +\n JOB_PRICE,\n inputSchema: z.object({\n urls: z.array(z.string()).min(1).max(1000).describe(\"The pages to extract (duplicates removed). Plan limits: Free 10, PAYG 50, Project 100, Bootstrap 500, Startup and Growth 1,000.\"),\n ...jobFields,\n }),\n execute: async (input) => {\n const { wait_seconds, limit, include_content, ...body } = input;\n return startAndWait(\n () => c.extract.batch(body as Parameters<typeof c.extract.batch>[0]),\n (id, q) => c.extract.batchStatus(id, q),\n { wait_seconds, limit, include_content },\n pollMs,\n );\n },\n });\n}\n\n/** A batch's progress and page results (GET /api/v1/extract/batch/{id}). Free. */\nexport function scavioBatchStatus(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Read a batch extract's progress and its page results by job id via the Scavio API, paged by cursor: `data` { status, pages, credits_used, results: [{ url, status, content }], next_cursor }. Results are kept for 3 days after the batch finishes. Free: reading a job costs 0 credits.\",\n inputSchema: jobStatusSchema,\n execute: async ({ id, limit, ...q }) =>\n (await c.extract.batchStatus(id, { ...q, limit: limit ?? JOB_RESULTS_DEFAULT_LIMIT })) as unknown as Record<string, unknown>,\n });\n}\n\n/**\n * All Scavio tools as an object keyed by tool name, ready to spread into the\n * `tools` option of `generateText` / `streamText`.\n */\nexport function scavioTools(config?: ScavioToolConfig) {\n return {\n scavio_extract: scavioExtract(config),\n scavio_search: scavioSearch(config),\n scavio_youtube_search: scavioYoutubeSearch(config),\n scavio_youtube_video: scavioYoutubeVideo(config),\n scavio_youtube_transcript: scavioYoutubeTranscript(config),\n scavio_youtube_comments: scavioYoutubeComments(config),\n scavio_youtube_channel: scavioYoutubeChannel(config),\n scavio_reddit_search: scavioRedditSearch(config),\n scavio_amazon_search: scavioAmazonSearch(config),\n scavio_amazon_offers: scavioAmazonOffers(config),\n scavio_walmart_search: scavioWalmartSearch(config),\n scavio_tiktok_search: scavioTiktokSearch(config),\n scavio_instagram_search: scavioInstagramSearch(config),\n ...(config?.enableCrawl\n ? {\n scavio_map_website: scavioMapWebsite(config),\n scavio_crawl_website: scavioCrawlWebsite(config),\n scavio_crawl_status: scavioCrawlStatus(config),\n scavio_batch_extract: scavioBatchExtract(config),\n scavio_batch_status: scavioBatchStatus(config),\n }\n : {}),\n };\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -5,9 +5,34 @@ interface ScavioToolConfig extends ScavioConfig {
5
5
  /**
6
6
  * Max number of items to keep in the tool's result list. Defaults to 10.
7
7
  * Trimmed inside `data` on every platform except Google, whose body is flat.
8
+ * Ignored by `scavioExtract`, which returns page content rather than a list.
8
9
  */
9
10
  maxResults?: number;
11
+ /**
12
+ * Add the five website tools (map, crawl, crawl status, batch extract, batch
13
+ * status) to `scavioTools()`. Off by default: a crawl bills per page. The
14
+ * individual factories (`scavioCrawlWebsite` and friends) work regardless.
15
+ */
16
+ enableCrawl?: boolean;
17
+ /** Milliseconds between progress polls while a crawl or batch tool waits. Default 3000. */
18
+ pollIntervalMs?: number;
10
19
  }
20
+ /**
21
+ * Read any URL (/api/v1/extract).
22
+ *
23
+ * The one tool here that is not tied to a platform, and the only one `maxResults`
24
+ * does not touch: extract returns page CONTENT, not a result list, so there is
25
+ * nothing to trim and the body is returned whole. `extract` is a TOP-LEVEL
26
+ * method on the SDK client - `c.extract({ url })`, never `c.extract.extract()`.
27
+ *
28
+ * Credits are a function of `mode`, not a per-call constant: "normal" 1,
29
+ * "advanced" 1, "ultra" 2. Only a successful read is billed.
30
+ */
31
+ declare function scavioExtract(config?: ScavioToolConfig): ai.Tool<{
32
+ url: string;
33
+ format?: "html" | "markdown" | "text" | undefined;
34
+ mode?: "normal" | "advanced" | "ultra" | undefined;
35
+ }, Record<string, unknown>>;
11
36
  /** Google web search (/api/v2/google, 1 credit). */
12
37
  declare function scavioSearch(config?: ScavioToolConfig): ai.Tool<{
13
38
  query: string;
@@ -33,8 +58,8 @@ declare function scavioYoutubeVideo(config?: ScavioToolConfig): ai.Tool<{
33
58
  /** YouTube video transcript / subtitles (8 credits). */
34
59
  declare function scavioYoutubeTranscript(config?: ScavioToolConfig): ai.Tool<{
35
60
  video_id: string;
36
- language?: string | undefined;
37
61
  format?: "text" | "srt" | undefined;
62
+ language?: string | undefined;
38
63
  }, Record<string, unknown>>;
39
64
  /** YouTube video comments (1 credit). */
40
65
  declare function scavioYoutubeComments(config?: ScavioToolConfig): ai.Tool<{
@@ -87,11 +112,117 @@ declare function scavioTiktokSearch(config?: ScavioToolConfig): ai.Tool<{
87
112
  declare function scavioInstagramSearch(config?: ScavioToolConfig): ai.Tool<{
88
113
  keyword: string;
89
114
  }, Record<string, unknown>>;
115
+ /** Map a website's URLs (/api/v1/extract/map). 1 credit on 'normal'. */
116
+ declare function scavioMapWebsite(config?: ScavioToolConfig): ai.Tool<{
117
+ url: string;
118
+ mode?: "normal" | "advanced" | "ultra" | undefined;
119
+ limit?: number | undefined;
120
+ search?: string | undefined;
121
+ sitemap?: "include" | "only" | "skip" | undefined;
122
+ include_subdomains?: boolean | undefined;
123
+ include_paths?: string[] | undefined;
124
+ exclude_paths?: string[] | undefined;
125
+ ignore_query_parameters?: boolean | undefined;
126
+ }, Record<string, unknown>>;
127
+ /** Crawl a website (/api/v1/extract/crawl), then wait (bounded) for it. */
128
+ declare function scavioCrawlWebsite(config?: ScavioToolConfig): ai.Tool<{
129
+ url: string;
130
+ format?: "html" | "markdown" | "text" | undefined;
131
+ mode?: "normal" | "advanced" | "ultra" | undefined;
132
+ limit?: number | undefined;
133
+ include_content?: boolean | undefined;
134
+ sitemap?: "include" | "only" | "skip" | undefined;
135
+ include_paths?: string[] | undefined;
136
+ exclude_paths?: string[] | undefined;
137
+ ignore_query_parameters?: boolean | undefined;
138
+ max_pages?: number | undefined;
139
+ max_depth?: number | undefined;
140
+ allow_subdomains?: boolean | undefined;
141
+ wait_seconds?: number | undefined;
142
+ }, Record<string, unknown>>;
143
+ /** A crawl's progress and page results (GET /api/v1/extract/crawl/{id}). Free. */
144
+ declare function scavioCrawlStatus(config?: ScavioToolConfig): ai.Tool<{
145
+ id: string;
146
+ status?: "failed" | "succeeded" | "skipped" | undefined;
147
+ cursor?: string | undefined;
148
+ limit?: number | undefined;
149
+ include_content?: boolean | undefined;
150
+ }, Record<string, unknown>>;
151
+ /** Extract a list of URLs in one job (/api/v1/extract/batch), then wait (bounded). */
152
+ declare function scavioBatchExtract(config?: ScavioToolConfig): ai.Tool<{
153
+ urls: string[];
154
+ format?: "html" | "markdown" | "text" | undefined;
155
+ mode?: "normal" | "advanced" | "ultra" | undefined;
156
+ limit?: number | undefined;
157
+ include_content?: boolean | undefined;
158
+ wait_seconds?: number | undefined;
159
+ }, Record<string, unknown>>;
160
+ /** A batch's progress and page results (GET /api/v1/extract/batch/{id}). Free. */
161
+ declare function scavioBatchStatus(config?: ScavioToolConfig): ai.Tool<{
162
+ id: string;
163
+ status?: "failed" | "succeeded" | "skipped" | undefined;
164
+ cursor?: string | undefined;
165
+ limit?: number | undefined;
166
+ include_content?: boolean | undefined;
167
+ }, Record<string, unknown>>;
90
168
  /**
91
169
  * All Scavio tools as an object keyed by tool name, ready to spread into the
92
170
  * `tools` option of `generateText` / `streamText`.
93
171
  */
94
172
  declare function scavioTools(config?: ScavioToolConfig): {
173
+ scavio_map_website?: ai.Tool<{
174
+ url: string;
175
+ mode?: "normal" | "advanced" | "ultra" | undefined;
176
+ limit?: number | undefined;
177
+ search?: string | undefined;
178
+ sitemap?: "include" | "only" | "skip" | undefined;
179
+ include_subdomains?: boolean | undefined;
180
+ include_paths?: string[] | undefined;
181
+ exclude_paths?: string[] | undefined;
182
+ ignore_query_parameters?: boolean | undefined;
183
+ }, Record<string, unknown>> | undefined;
184
+ scavio_crawl_website?: ai.Tool<{
185
+ url: string;
186
+ format?: "html" | "markdown" | "text" | undefined;
187
+ mode?: "normal" | "advanced" | "ultra" | undefined;
188
+ limit?: number | undefined;
189
+ include_content?: boolean | undefined;
190
+ sitemap?: "include" | "only" | "skip" | undefined;
191
+ include_paths?: string[] | undefined;
192
+ exclude_paths?: string[] | undefined;
193
+ ignore_query_parameters?: boolean | undefined;
194
+ max_pages?: number | undefined;
195
+ max_depth?: number | undefined;
196
+ allow_subdomains?: boolean | undefined;
197
+ wait_seconds?: number | undefined;
198
+ }, Record<string, unknown>> | undefined;
199
+ scavio_crawl_status?: ai.Tool<{
200
+ id: string;
201
+ status?: "failed" | "succeeded" | "skipped" | undefined;
202
+ cursor?: string | undefined;
203
+ limit?: number | undefined;
204
+ include_content?: boolean | undefined;
205
+ }, Record<string, unknown>> | undefined;
206
+ scavio_batch_extract?: ai.Tool<{
207
+ urls: string[];
208
+ format?: "html" | "markdown" | "text" | undefined;
209
+ mode?: "normal" | "advanced" | "ultra" | undefined;
210
+ limit?: number | undefined;
211
+ include_content?: boolean | undefined;
212
+ wait_seconds?: number | undefined;
213
+ }, Record<string, unknown>> | undefined;
214
+ scavio_batch_status?: ai.Tool<{
215
+ id: string;
216
+ status?: "failed" | "succeeded" | "skipped" | undefined;
217
+ cursor?: string | undefined;
218
+ limit?: number | undefined;
219
+ include_content?: boolean | undefined;
220
+ }, Record<string, unknown>> | undefined;
221
+ scavio_extract: ai.Tool<{
222
+ url: string;
223
+ format?: "html" | "markdown" | "text" | undefined;
224
+ mode?: "normal" | "advanced" | "ultra" | undefined;
225
+ }, Record<string, unknown>>;
95
226
  scavio_search: ai.Tool<{
96
227
  query: string;
97
228
  countryCode?: string | undefined;
@@ -113,8 +244,8 @@ declare function scavioTools(config?: ScavioToolConfig): {
113
244
  }, Record<string, unknown>>;
114
245
  scavio_youtube_transcript: ai.Tool<{
115
246
  video_id: string;
116
- language?: string | undefined;
117
247
  format?: "text" | "srt" | undefined;
248
+ language?: string | undefined;
118
249
  }, Record<string, unknown>>;
119
250
  scavio_youtube_comments: ai.Tool<{
120
251
  video_id: string;
@@ -148,4 +279,4 @@ declare function scavioTools(config?: ScavioToolConfig): {
148
279
  }, Record<string, unknown>>;
149
280
  };
150
281
 
151
- export { type ScavioToolConfig, scavioAmazonOffers, scavioAmazonSearch, scavioInstagramSearch, scavioRedditSearch, scavioSearch, scavioTiktokSearch, scavioTools, scavioWalmartSearch, scavioYoutubeChannel, scavioYoutubeComments, scavioYoutubeSearch, scavioYoutubeTranscript, scavioYoutubeVideo };
282
+ export { type ScavioToolConfig, scavioAmazonOffers, scavioAmazonSearch, scavioBatchExtract, scavioBatchStatus, scavioCrawlStatus, scavioCrawlWebsite, scavioExtract, scavioInstagramSearch, scavioMapWebsite, scavioRedditSearch, scavioSearch, scavioTiktokSearch, scavioTools, scavioWalmartSearch, scavioYoutubeChannel, scavioYoutubeComments, scavioYoutubeSearch, scavioYoutubeTranscript, scavioYoutubeVideo };
package/dist/index.d.ts CHANGED
@@ -5,9 +5,34 @@ interface ScavioToolConfig extends ScavioConfig {
5
5
  /**
6
6
  * Max number of items to keep in the tool's result list. Defaults to 10.
7
7
  * Trimmed inside `data` on every platform except Google, whose body is flat.
8
+ * Ignored by `scavioExtract`, which returns page content rather than a list.
8
9
  */
9
10
  maxResults?: number;
11
+ /**
12
+ * Add the five website tools (map, crawl, crawl status, batch extract, batch
13
+ * status) to `scavioTools()`. Off by default: a crawl bills per page. The
14
+ * individual factories (`scavioCrawlWebsite` and friends) work regardless.
15
+ */
16
+ enableCrawl?: boolean;
17
+ /** Milliseconds between progress polls while a crawl or batch tool waits. Default 3000. */
18
+ pollIntervalMs?: number;
10
19
  }
20
+ /**
21
+ * Read any URL (/api/v1/extract).
22
+ *
23
+ * The one tool here that is not tied to a platform, and the only one `maxResults`
24
+ * does not touch: extract returns page CONTENT, not a result list, so there is
25
+ * nothing to trim and the body is returned whole. `extract` is a TOP-LEVEL
26
+ * method on the SDK client - `c.extract({ url })`, never `c.extract.extract()`.
27
+ *
28
+ * Credits are a function of `mode`, not a per-call constant: "normal" 1,
29
+ * "advanced" 1, "ultra" 2. Only a successful read is billed.
30
+ */
31
+ declare function scavioExtract(config?: ScavioToolConfig): ai.Tool<{
32
+ url: string;
33
+ format?: "html" | "markdown" | "text" | undefined;
34
+ mode?: "normal" | "advanced" | "ultra" | undefined;
35
+ }, Record<string, unknown>>;
11
36
  /** Google web search (/api/v2/google, 1 credit). */
12
37
  declare function scavioSearch(config?: ScavioToolConfig): ai.Tool<{
13
38
  query: string;
@@ -33,8 +58,8 @@ declare function scavioYoutubeVideo(config?: ScavioToolConfig): ai.Tool<{
33
58
  /** YouTube video transcript / subtitles (8 credits). */
34
59
  declare function scavioYoutubeTranscript(config?: ScavioToolConfig): ai.Tool<{
35
60
  video_id: string;
36
- language?: string | undefined;
37
61
  format?: "text" | "srt" | undefined;
62
+ language?: string | undefined;
38
63
  }, Record<string, unknown>>;
39
64
  /** YouTube video comments (1 credit). */
40
65
  declare function scavioYoutubeComments(config?: ScavioToolConfig): ai.Tool<{
@@ -87,11 +112,117 @@ declare function scavioTiktokSearch(config?: ScavioToolConfig): ai.Tool<{
87
112
  declare function scavioInstagramSearch(config?: ScavioToolConfig): ai.Tool<{
88
113
  keyword: string;
89
114
  }, Record<string, unknown>>;
115
+ /** Map a website's URLs (/api/v1/extract/map). 1 credit on 'normal'. */
116
+ declare function scavioMapWebsite(config?: ScavioToolConfig): ai.Tool<{
117
+ url: string;
118
+ mode?: "normal" | "advanced" | "ultra" | undefined;
119
+ limit?: number | undefined;
120
+ search?: string | undefined;
121
+ sitemap?: "include" | "only" | "skip" | undefined;
122
+ include_subdomains?: boolean | undefined;
123
+ include_paths?: string[] | undefined;
124
+ exclude_paths?: string[] | undefined;
125
+ ignore_query_parameters?: boolean | undefined;
126
+ }, Record<string, unknown>>;
127
+ /** Crawl a website (/api/v1/extract/crawl), then wait (bounded) for it. */
128
+ declare function scavioCrawlWebsite(config?: ScavioToolConfig): ai.Tool<{
129
+ url: string;
130
+ format?: "html" | "markdown" | "text" | undefined;
131
+ mode?: "normal" | "advanced" | "ultra" | undefined;
132
+ limit?: number | undefined;
133
+ include_content?: boolean | undefined;
134
+ sitemap?: "include" | "only" | "skip" | undefined;
135
+ include_paths?: string[] | undefined;
136
+ exclude_paths?: string[] | undefined;
137
+ ignore_query_parameters?: boolean | undefined;
138
+ max_pages?: number | undefined;
139
+ max_depth?: number | undefined;
140
+ allow_subdomains?: boolean | undefined;
141
+ wait_seconds?: number | undefined;
142
+ }, Record<string, unknown>>;
143
+ /** A crawl's progress and page results (GET /api/v1/extract/crawl/{id}). Free. */
144
+ declare function scavioCrawlStatus(config?: ScavioToolConfig): ai.Tool<{
145
+ id: string;
146
+ status?: "failed" | "succeeded" | "skipped" | undefined;
147
+ cursor?: string | undefined;
148
+ limit?: number | undefined;
149
+ include_content?: boolean | undefined;
150
+ }, Record<string, unknown>>;
151
+ /** Extract a list of URLs in one job (/api/v1/extract/batch), then wait (bounded). */
152
+ declare function scavioBatchExtract(config?: ScavioToolConfig): ai.Tool<{
153
+ urls: string[];
154
+ format?: "html" | "markdown" | "text" | undefined;
155
+ mode?: "normal" | "advanced" | "ultra" | undefined;
156
+ limit?: number | undefined;
157
+ include_content?: boolean | undefined;
158
+ wait_seconds?: number | undefined;
159
+ }, Record<string, unknown>>;
160
+ /** A batch's progress and page results (GET /api/v1/extract/batch/{id}). Free. */
161
+ declare function scavioBatchStatus(config?: ScavioToolConfig): ai.Tool<{
162
+ id: string;
163
+ status?: "failed" | "succeeded" | "skipped" | undefined;
164
+ cursor?: string | undefined;
165
+ limit?: number | undefined;
166
+ include_content?: boolean | undefined;
167
+ }, Record<string, unknown>>;
90
168
  /**
91
169
  * All Scavio tools as an object keyed by tool name, ready to spread into the
92
170
  * `tools` option of `generateText` / `streamText`.
93
171
  */
94
172
  declare function scavioTools(config?: ScavioToolConfig): {
173
+ scavio_map_website?: ai.Tool<{
174
+ url: string;
175
+ mode?: "normal" | "advanced" | "ultra" | undefined;
176
+ limit?: number | undefined;
177
+ search?: string | undefined;
178
+ sitemap?: "include" | "only" | "skip" | undefined;
179
+ include_subdomains?: boolean | undefined;
180
+ include_paths?: string[] | undefined;
181
+ exclude_paths?: string[] | undefined;
182
+ ignore_query_parameters?: boolean | undefined;
183
+ }, Record<string, unknown>> | undefined;
184
+ scavio_crawl_website?: ai.Tool<{
185
+ url: string;
186
+ format?: "html" | "markdown" | "text" | undefined;
187
+ mode?: "normal" | "advanced" | "ultra" | undefined;
188
+ limit?: number | undefined;
189
+ include_content?: boolean | undefined;
190
+ sitemap?: "include" | "only" | "skip" | undefined;
191
+ include_paths?: string[] | undefined;
192
+ exclude_paths?: string[] | undefined;
193
+ ignore_query_parameters?: boolean | undefined;
194
+ max_pages?: number | undefined;
195
+ max_depth?: number | undefined;
196
+ allow_subdomains?: boolean | undefined;
197
+ wait_seconds?: number | undefined;
198
+ }, Record<string, unknown>> | undefined;
199
+ scavio_crawl_status?: ai.Tool<{
200
+ id: string;
201
+ status?: "failed" | "succeeded" | "skipped" | undefined;
202
+ cursor?: string | undefined;
203
+ limit?: number | undefined;
204
+ include_content?: boolean | undefined;
205
+ }, Record<string, unknown>> | undefined;
206
+ scavio_batch_extract?: ai.Tool<{
207
+ urls: string[];
208
+ format?: "html" | "markdown" | "text" | undefined;
209
+ mode?: "normal" | "advanced" | "ultra" | undefined;
210
+ limit?: number | undefined;
211
+ include_content?: boolean | undefined;
212
+ wait_seconds?: number | undefined;
213
+ }, Record<string, unknown>> | undefined;
214
+ scavio_batch_status?: ai.Tool<{
215
+ id: string;
216
+ status?: "failed" | "succeeded" | "skipped" | undefined;
217
+ cursor?: string | undefined;
218
+ limit?: number | undefined;
219
+ include_content?: boolean | undefined;
220
+ }, Record<string, unknown>> | undefined;
221
+ scavio_extract: ai.Tool<{
222
+ url: string;
223
+ format?: "html" | "markdown" | "text" | undefined;
224
+ mode?: "normal" | "advanced" | "ultra" | undefined;
225
+ }, Record<string, unknown>>;
95
226
  scavio_search: ai.Tool<{
96
227
  query: string;
97
228
  countryCode?: string | undefined;
@@ -113,8 +244,8 @@ declare function scavioTools(config?: ScavioToolConfig): {
113
244
  }, Record<string, unknown>>;
114
245
  scavio_youtube_transcript: ai.Tool<{
115
246
  video_id: string;
116
- language?: string | undefined;
117
247
  format?: "text" | "srt" | undefined;
248
+ language?: string | undefined;
118
249
  }, Record<string, unknown>>;
119
250
  scavio_youtube_comments: ai.Tool<{
120
251
  video_id: string;
@@ -148,4 +279,4 @@ declare function scavioTools(config?: ScavioToolConfig): {
148
279
  }, Record<string, unknown>>;
149
280
  };
150
281
 
151
- export { type ScavioToolConfig, scavioAmazonOffers, scavioAmazonSearch, scavioInstagramSearch, scavioRedditSearch, scavioSearch, scavioTiktokSearch, scavioTools, scavioWalmartSearch, scavioYoutubeChannel, scavioYoutubeComments, scavioYoutubeSearch, scavioYoutubeTranscript, scavioYoutubeVideo };
282
+ export { type ScavioToolConfig, scavioAmazonOffers, scavioAmazonSearch, scavioBatchExtract, scavioBatchStatus, scavioCrawlStatus, scavioCrawlWebsite, scavioExtract, scavioInstagramSearch, scavioMapWebsite, scavioRedditSearch, scavioSearch, scavioTiktokSearch, scavioTools, scavioWalmartSearch, scavioYoutubeChannel, scavioYoutubeComments, scavioYoutubeSearch, scavioYoutubeTranscript, scavioYoutubeVideo };
package/dist/index.js CHANGED
@@ -21,6 +21,24 @@ function trimData(res, key, max) {
21
21
  }
22
22
  return res;
23
23
  }
24
+ function scavioExtract(config) {
25
+ const c = client(config);
26
+ return tool({
27
+ description: "Read any web page via the Scavio API and get it back as clean Markdown (default), plain text, or raw HTML. Use it on any URL, including one returned by the search tools. Returns `data.content` alongside `data.url`, `data.format`, `data.mode` and `data.content_length`. Cost depends on `mode`: 1 credit on 'normal' and 'advanced', 2 on 'ultra'; a dead link, bot wall or timeout is not billed.",
28
+ inputSchema: z.object({
29
+ url: z.string().describe(
30
+ "The page to read (1-2048 characters). http(s) only; a bare host is upgraded to https, and loopback, private, link-local and metadata hosts are rejected."
31
+ ),
32
+ format: z.enum(["html", "markdown", "text"]).optional().describe(
33
+ "Output format (default 'markdown'): 'markdown' is a readability extraction with page chrome stripped, 'text' is that flattened to plain text, 'html' is the raw page."
34
+ ),
35
+ mode: z.enum(["normal", "advanced", "ultra"]).optional().describe(
36
+ "Fetch tier, and the parameter that sets the price: 'normal' (default) is a plain fetch and costs 1 credit, 'advanced' renders JavaScript-built pages and costs 1, 'ultra' reaches the hardest pages and costs 2. Start on 'normal'."
37
+ )
38
+ }),
39
+ execute: async ({ url, format, mode }) => c.extract({ url, format, mode })
40
+ });
41
+ }
24
42
  function scavioSearch(config) {
25
43
  const c = client(config);
26
44
  const max = config?.maxResults ?? 10;
@@ -196,8 +214,133 @@ function scavioInstagramSearch(config) {
196
214
  execute: async ({ keyword }) => trimData(await c.instagram.searchUsers({ keyword }), "users", max)
197
215
  });
198
216
  }
217
+ var JOB_POLL_INTERVAL_MS = 3e3;
218
+ var JOB_WAIT_DEFAULT_SECONDS = 45;
219
+ var JOB_WAIT_MAX_SECONDS = 300;
220
+ var JOB_RESULTS_DEFAULT_LIMIT = 10;
221
+ var JOB_TERMINAL = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
222
+ var sleep = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms));
223
+ async function waitForJob(status, id, waitSeconds, pollMs, query) {
224
+ const deadline = Date.now() + Math.max(0, Math.min(waitSeconds, JOB_WAIT_MAX_SECONDS)) * 1e3;
225
+ for (; ; ) {
226
+ const remaining = deadline - Date.now();
227
+ if (remaining <= 0) break;
228
+ await sleep(Math.min(pollMs, remaining));
229
+ const probe = await status(id, { limit: 1, include_content: false });
230
+ if (JOB_TERMINAL.has(String(probe?.data?.status))) break;
231
+ }
232
+ return await status(id, query);
233
+ }
234
+ async function startAndWait(start, status, input, pollMs) {
235
+ const created = await start();
236
+ const id = created?.data?.id;
237
+ const wait = input.wait_seconds ?? JOB_WAIT_DEFAULT_SECONDS;
238
+ if (!id || wait <= 0) return created;
239
+ const query = { limit: input.limit ?? JOB_RESULTS_DEFAULT_LIMIT };
240
+ if (input.include_content !== void 0) query.include_content = input.include_content;
241
+ return waitForJob(status, id, wait, pollMs, query);
242
+ }
243
+ var MODE_DESCRIPTION = "Fetch tier, and the parameter that sets the price: 'normal' (default) is the standard fetch, 'advanced' renders JavaScript-built pages, 'ultra' reaches the hardest pages.";
244
+ var PATHS_DESCRIPTION = "Path globs (max 20). '*' matches within one path segment, '**' across segments; a pattern without wildcards matches that path and everything under it. Example: ['/blog/**'].";
245
+ var JOB_PRICE = "Billed per SUCCESSFUL page at Extract's price for the mode: 'normal' and 'advanced' 1 credit, 'ultra' 2. Failed and skipped pages are free, and if the balance runs out the job stops cleanly.";
246
+ var jobFields = {
247
+ format: z.enum(["html", "markdown", "text"]).optional().describe("Format for each page, as on extract (default 'markdown')."),
248
+ mode: z.enum(["normal", "advanced", "ultra"]).optional().describe(MODE_DESCRIPTION),
249
+ wait_seconds: z.number().int().min(0).max(JOB_WAIT_MAX_SECONDS).optional().describe("Seconds to wait for the job to finish before returning, 0-300 (default 45). 0 returns the job id at once. A job still running when the wait ends keeps going; read it later with its status tool."),
250
+ limit: z.number().int().min(1).max(100).optional().describe("Results per response, 1-100 (default 10, to keep page content inside the context window); page on with next_cursor."),
251
+ include_content: z.boolean().optional().describe("Set false to list results without their page content (default true).")
252
+ };
253
+ var jobStatusSchema = z.object({
254
+ id: z.string().describe("Job id returned when the job was started (data.id)."),
255
+ cursor: z.string().optional().describe("next_cursor from the previous response, to read the next page."),
256
+ limit: jobFields.limit,
257
+ status: z.enum(["succeeded", "failed", "skipped"]).optional().describe("Only results with this status."),
258
+ include_content: jobFields.include_content
259
+ });
260
+ function scavioMapWebsite(config) {
261
+ const c = client(config);
262
+ return tool({
263
+ description: "List a website's page URLs via the Scavio API, gathered from its sitemaps and its start page, deduplicated, filtered by path or search words and limited: `data.links` [{ url, source, lastmod }], `data.total_found`, `data.truncated`. Pages the site's robots.txt disallows are left out. Use it to find the right pages before extracting or crawling. Costs 1 credit on 'normal'; up to 2 on 'advanced' and up to 10 on 'ultra', priced by what the call needed.",
264
+ inputSchema: z.object({
265
+ url: z.string().describe("The site to map. A bare host is upgraded to https."),
266
+ search: z.string().optional().describe("Only return URLs containing every word of this text (case-insensitive)."),
267
+ limit: z.number().int().min(1).max(5e3).optional().describe("Maximum links to return, 1-5000. Default 1000 (or the plan's limit if lower: Free 500, PAYG 1,000, paid plans 5,000)."),
268
+ sitemap: z.enum(["include", "only", "skip"]).optional().describe("'include' combines the site's sitemaps with the start page's links (default); 'only' uses sitemaps alone; 'skip' uses page links alone."),
269
+ include_subdomains: z.boolean().optional().describe("Also return URLs on subdomains of the site (default false)."),
270
+ include_paths: z.array(z.string()).optional().describe("Keep only URLs matching these. " + PATHS_DESCRIPTION),
271
+ exclude_paths: z.array(z.string()).optional().describe("Drop URLs matching these. " + PATHS_DESCRIPTION),
272
+ ignore_query_parameters: z.boolean().optional().describe("Treat URLs that differ only by query string as one URL (default true)."),
273
+ mode: jobFields.mode
274
+ }),
275
+ execute: async (input) => await c.extract.map(input)
276
+ });
277
+ }
278
+ function scavioCrawlWebsite(config) {
279
+ const c = client(config);
280
+ const pollMs = config?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS;
281
+ return tool({
282
+ description: "Crawl a website from one start URL via the Scavio API: same-site pages are discovered and extracted breadth-first within the page, depth and path limits, each returned as Markdown, text or HTML. Pages the site's robots.txt disallows are skipped. Waits up to wait_seconds (default 45) and returns `data` { id, status, pages, credits_used, results, next_cursor }; if status is still queued or running, call scavio_crawl_status with the id later. " + JOB_PRICE,
283
+ inputSchema: z.object({
284
+ url: z.string().describe("Where the crawl starts. Only pages on the same site are crawled."),
285
+ max_pages: z.number().int().min(1).max(1e4).optional().describe("Maximum pages to fetch. Default 100. Plan limits: Free 10, PAYG 100, Project 500, Bootstrap 2,000, Startup 5,000, Growth 10,000."),
286
+ max_depth: z.number().int().min(0).max(10).optional().describe("How many links away from the start page to follow, 0-10 (default 3). 0 fetches only the start page."),
287
+ include_paths: z.array(z.string()).optional().describe("Crawl only paths matching these. " + PATHS_DESCRIPTION),
288
+ exclude_paths: z.array(z.string()).optional().describe("Skip paths matching these. " + PATHS_DESCRIPTION),
289
+ allow_subdomains: z.boolean().optional().describe("Also crawl subdomains of the site (default false)."),
290
+ ignore_query_parameters: z.boolean().optional().describe("Treat URLs that differ only by query string as one page (default true)."),
291
+ sitemap: z.enum(["include", "skip", "only"]).optional().describe("'include' also starts from the site's sitemap (default); 'skip' follows links only; 'only' fetches sitemap pages without following links."),
292
+ ...jobFields
293
+ }),
294
+ execute: async (input) => {
295
+ const { wait_seconds, limit, include_content, ...body } = input;
296
+ return startAndWait(
297
+ () => c.extract.crawl(body),
298
+ (id, q) => c.extract.crawlStatus(id, q),
299
+ { wait_seconds, limit, include_content },
300
+ pollMs
301
+ );
302
+ }
303
+ });
304
+ }
305
+ function scavioCrawlStatus(config) {
306
+ const c = client(config);
307
+ return tool({
308
+ description: "Read a crawl's progress and its page results by job id via the Scavio API, paged by cursor: `data` { status, stopped_reason, pages, credits_used, results: [{ url, status, content }], next_cursor }. Results are kept for 3 days after the crawl finishes. Free: reading a job costs 0 credits.",
309
+ inputSchema: jobStatusSchema,
310
+ execute: async ({ id, limit, ...q }) => await c.extract.crawlStatus(id, { ...q, limit: limit ?? JOB_RESULTS_DEFAULT_LIMIT })
311
+ });
312
+ }
313
+ function scavioBatchExtract(config) {
314
+ const c = client(config);
315
+ const pollMs = config?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS;
316
+ return tool({
317
+ description: "Extract a list of URLs (up to 1,000, plan-limited) in one job via the Scavio API, each returned as Markdown, text or HTML exactly like scavio_extract. Waits up to wait_seconds (default 45) and returns `data` { id, status, pages, credits_used, results, next_cursor }; if status is still queued or running, call scavio_batch_status with the id later. " + JOB_PRICE,
318
+ inputSchema: z.object({
319
+ urls: z.array(z.string()).min(1).max(1e3).describe("The pages to extract (duplicates removed). Plan limits: Free 10, PAYG 50, Project 100, Bootstrap 500, Startup and Growth 1,000."),
320
+ ...jobFields
321
+ }),
322
+ execute: async (input) => {
323
+ const { wait_seconds, limit, include_content, ...body } = input;
324
+ return startAndWait(
325
+ () => c.extract.batch(body),
326
+ (id, q) => c.extract.batchStatus(id, q),
327
+ { wait_seconds, limit, include_content },
328
+ pollMs
329
+ );
330
+ }
331
+ });
332
+ }
333
+ function scavioBatchStatus(config) {
334
+ const c = client(config);
335
+ return tool({
336
+ description: "Read a batch extract's progress and its page results by job id via the Scavio API, paged by cursor: `data` { status, pages, credits_used, results: [{ url, status, content }], next_cursor }. Results are kept for 3 days after the batch finishes. Free: reading a job costs 0 credits.",
337
+ inputSchema: jobStatusSchema,
338
+ execute: async ({ id, limit, ...q }) => await c.extract.batchStatus(id, { ...q, limit: limit ?? JOB_RESULTS_DEFAULT_LIMIT })
339
+ });
340
+ }
199
341
  function scavioTools(config) {
200
342
  return {
343
+ scavio_extract: scavioExtract(config),
201
344
  scavio_search: scavioSearch(config),
202
345
  scavio_youtube_search: scavioYoutubeSearch(config),
203
346
  scavio_youtube_video: scavioYoutubeVideo(config),
@@ -209,13 +352,26 @@ function scavioTools(config) {
209
352
  scavio_amazon_offers: scavioAmazonOffers(config),
210
353
  scavio_walmart_search: scavioWalmartSearch(config),
211
354
  scavio_tiktok_search: scavioTiktokSearch(config),
212
- scavio_instagram_search: scavioInstagramSearch(config)
355
+ scavio_instagram_search: scavioInstagramSearch(config),
356
+ ...config?.enableCrawl ? {
357
+ scavio_map_website: scavioMapWebsite(config),
358
+ scavio_crawl_website: scavioCrawlWebsite(config),
359
+ scavio_crawl_status: scavioCrawlStatus(config),
360
+ scavio_batch_extract: scavioBatchExtract(config),
361
+ scavio_batch_status: scavioBatchStatus(config)
362
+ } : {}
213
363
  };
214
364
  }
215
365
  export {
216
366
  scavioAmazonOffers,
217
367
  scavioAmazonSearch,
368
+ scavioBatchExtract,
369
+ scavioBatchStatus,
370
+ scavioCrawlStatus,
371
+ scavioCrawlWebsite,
372
+ scavioExtract,
218
373
  scavioInstagramSearch,
374
+ scavioMapWebsite,
219
375
  scavioRedditSearch,
220
376
  scavioSearch,
221
377
  scavioTiktokSearch,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport { Scavio, type ScavioConfig, type GoogleSearchOptions } from \"scavio\";\n\nexport interface ScavioToolConfig extends ScavioConfig {\n /**\n * Max number of items to keep in the tool's result list. Defaults to 10.\n * Trimmed inside `data` on every platform except Google, whose body is flat.\n */\n maxResults?: number;\n}\n\nfunction client(config?: ScavioToolConfig): Scavio {\n return new Scavio({ apiKey: config?.apiKey });\n}\n\n/**\n * Google is the ONLY family with a flat body: `organic_results` and friends sit\n * at the top level, next to `response_time` / `credits_used` / `credits_remaining`.\n */\nfunction trimFlat(res: Record<string, unknown>, key: string, max: number): Record<string, unknown> {\n const list = res[key];\n if (Array.isArray(list) && list.length > max) {\n return { ...res, [key]: list.slice(0, max) };\n }\n return res;\n}\n\n/**\n * Every non-Google endpoint nests its payload under `data` - the response is\n * `{ data: { products: [...] }, response_time, credits_used, credits_remaining }`.\n * Trimming the top level is therefore a silent no-op, so those tools trim\n * inside `data`.\n */\nfunction trimData(res: Record<string, unknown>, key: string, max: number): Record<string, unknown> {\n const data = res.data;\n if (!data || typeof data !== \"object\") return res;\n const list = (data as Record<string, unknown>)[key];\n if (Array.isArray(list) && list.length > max) {\n return { ...res, data: { ...(data as Record<string, unknown>), [key]: list.slice(0, max) } };\n }\n return res;\n}\n\n/** Google web search (/api/v2/google, 1 credit). */\nexport function scavioSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search the web with Google via the Scavio API (1 credit). Returns real-time organic search results, each with a title, link, and snippet, under `organic_results`.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n countryCode: z.string().optional().describe('Two-letter country code to localize results, e.g. \"us\".'),\n language: z.string().optional().describe('Two-letter UI language code, e.g. \"en\".'),\n page: z.number().int().optional().describe(\"1-based result page; page 2 starts at result 10.\"),\n device: z.enum([\"desktop\", \"mobile\"]).optional().describe(\"Device to emulate.\"),\n nfpr: z.boolean().optional().describe(\"Disable spelling auto-correction / similar-result substitution when true.\"),\n }),\n execute: async ({ query, countryCode, language, page, device, nfpr }) => {\n const params: GoogleSearchOptions = { query };\n if (countryCode) params.gl = countryCode;\n if (language) params.hl = language;\n if (page && page > 1) params.start = (page - 1) * 10;\n if (device) params.device = device;\n if (nfpr !== undefined) params.nfpr = nfpr;\n return trimFlat(await c.google.search(params), \"organic_results\", max);\n },\n });\n}\n\n/** YouTube video search (2 credits). */\nexport function scavioYoutubeSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search YouTube for videos, channels, or playlists via the Scavio API (2 credits). Videos come back under `data.results`, with `data.channels` and `data.playlists` alongside.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n upload_date: z.string().optional().describe(\"Upload date filter, e.g. 'today', 'this_week', 'this_month'.\"),\n type: z.string().optional().describe(\"Result type: 'video', 'channel', 'playlist', 'movie'.\"),\n duration: z.string().optional().describe(\"Duration filter: 'short', 'medium', 'long'.\"),\n sort_by: z.string().optional().describe(\"Sort order: 'relevance', 'date', 'view_count', 'rating'.\"),\n cursor: z.string().optional().describe(\"Pagination cursor (`next_cursor`) from a prior response.\"),\n }),\n execute: async ({ query, upload_date, type, duration, sort_by, cursor }) =>\n trimData(\n await c.youtube.search({ query, upload_date, type, duration, sort_by, cursor } as Parameters<\n typeof c.youtube.search\n >[0]),\n \"results\",\n max,\n ),\n });\n}\n\n/** YouTube video details (1 credit). */\nexport function scavioYoutubeVideo(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch full details for a YouTube video (title, author, view count, description, captions, chapters) via the Scavio API.\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n }),\n execute: async ({ video_id }) => c.youtube.video({ video_id }),\n });\n}\n\n/** YouTube video transcript / subtitles (8 credits). */\nexport function scavioYoutubeTranscript(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch a YouTube video's transcript or timed subtitles via the Scavio API (8 credits).\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n language: z.string().optional().describe(\"Transcript language code (default 'en').\"),\n format: z.enum([\"text\", \"srt\"]).optional().describe(\"'text' for a plain transcript, 'srt' for timed subtitles.\"),\n }),\n execute: async ({ video_id, language, format }) =>\n c.youtube.transcript({ video_id, language, format } as Parameters<typeof c.youtube.transcript>[0]),\n });\n}\n\n/** YouTube video comments (1 credit). */\nexport function scavioYoutubeComments(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description: \"List comments on a YouTube video via the Scavio API.\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n cursor: z.string().optional().describe(\"Pagination cursor.\"),\n }),\n execute: async ({ video_id, cursor }) =>\n trimData(\n await c.youtube.comments({ video_id, cursor } as Parameters<typeof c.youtube.comments>[0]),\n \"comments\",\n max,\n ),\n });\n}\n\n/** YouTube channel details (1 credit). */\nexport function scavioYoutubeChannel(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch a YouTube channel's details (subscribers, video count, views, links) via the Scavio API.\",\n inputSchema: z.object({\n channel_id: z.string().describe(\"YouTube channel id, @handle, or channel URL.\"),\n }),\n execute: async ({ channel_id }) => c.youtube.channel({ channel_id }),\n });\n}\n\n/**\n * Reddit post search (1 credit).\n *\n * The endpoint takes `query` and `cursor` and nothing else - it cannot sort or\n * filter by type, so no such input is offered. The API silently ignores those\n * params, which would leave a model believing it had filtered when it had not.\n */\nexport function scavioRedditSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Reddit posts via the Scavio API (1 credit). Returns matching posts under `data.results` with `data.next_cursor` for the next page. Results cannot be sorted or filtered by type.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n cursor: z.string().optional().describe(\"Pagination cursor (`next_cursor`) from a prior response.\"),\n }),\n execute: async ({ query, cursor }) => trimData(await c.reddit.search({ query, cursor }), \"results\", max),\n });\n}\n\n/**\n * Amazon product search.\n *\n * `domain` was dropped in favour of `country`, a two-letter marketplace code -\n * the upstream provider changed in 2026-07 and no longer takes a domain\n * suffix. It still works on the wire as a deprecated alias, but a model should\n * only ever see one spelling of a param.\n */\nexport function scavioAmazonSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Amazon for products via the Scavio API. Results are unsorted and cannot be filtered by category, merchant or price.\",\n inputSchema: z.object({\n query: z.string().describe(\"The product search query.\"),\n country: z\n .string()\n .optional()\n .describe(\n \"Marketplace country code (ISO 3166-1 alpha-2), not a domain: us (default), gb (the UK is gb, not uk), de, fr, jp, ... An unknown code falls back to us.\"\n ),\n }),\n execute: async ({ query, country }) =>\n trimData(await c.amazon.search({ query, country }), \"products\", max),\n });\n}\n\n/** Every seller offer for one Amazon ASIN. */\nexport function scavioAmazonOffers(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"List every seller offer for one Amazon ASIN via the Scavio API: price, seller, condition, shipping, and which offer holds the buy box. Page 1 only.\",\n inputSchema: z.object({\n asin: z.string().describe(\"Amazon Standard Identification Number (ASIN) of the product.\"),\n country: z\n .string()\n .optional()\n .describe(\n \"Marketplace country code (ISO 3166-1 alpha-2), not a domain: us (default), gb (the UK is gb, not uk), de, fr, jp, ... An unknown code falls back to us.\"\n ),\n }),\n execute: async ({ asin, country }) =>\n trimData(await c.amazon.offers({ asin, country }), \"offers\", max),\n });\n}\n\n/** Walmart product search. */\nexport function scavioWalmartSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description: \"Search Walmart for products via the Scavio API. Products come back under `data.products`.\",\n inputSchema: z.object({\n query: z.string().describe(\"The product search query.\"),\n }),\n execute: async ({ query }) => trimData(await c.walmart.search({ query }), \"products\", max),\n });\n}\n\n/** TikTok video search. */\nexport function scavioTiktokSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search TikTok for videos by keyword via the Scavio API. Videos come back under `data.aweme_list`.\",\n inputSchema: z.object({\n keyword: z.string().describe(\"The search keyword.\"),\n sort_type: z.enum([\"0\", \"1\"]).optional().describe(\"Sort order: '0' relevance, '1' most likes.\"),\n publish_time: z\n .enum([\"0\", \"1\", \"7\", \"30\", \"90\", \"180\"])\n .optional()\n .describe(\"Publish window in days: '0' all time, '1', '7', '30', '90', '180'.\"),\n }),\n execute: async ({ keyword, sort_type, publish_time }) =>\n trimData(\n await c.tiktok.searchVideos({\n keyword,\n sort_type,\n publish_time,\n } as Parameters<typeof c.tiktok.searchVideos>[0]),\n \"aweme_list\",\n max,\n ),\n });\n}\n\n/** Instagram user search. */\nexport function scavioInstagramSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Instagram for users by keyword via the Scavio API (10 credits). Users come back under `data.users`.\",\n inputSchema: z.object({\n keyword: z.string().describe(\"The search keyword.\"),\n }),\n execute: async ({ keyword }) => trimData(await c.instagram.searchUsers({ keyword }), \"users\", max),\n });\n}\n\n/**\n * All Scavio tools as an object keyed by tool name, ready to spread into the\n * `tools` option of `generateText` / `streamText`.\n */\nexport function scavioTools(config?: ScavioToolConfig) {\n return {\n scavio_search: scavioSearch(config),\n scavio_youtube_search: scavioYoutubeSearch(config),\n scavio_youtube_video: scavioYoutubeVideo(config),\n scavio_youtube_transcript: scavioYoutubeTranscript(config),\n scavio_youtube_comments: scavioYoutubeComments(config),\n scavio_youtube_channel: scavioYoutubeChannel(config),\n scavio_reddit_search: scavioRedditSearch(config),\n scavio_amazon_search: scavioAmazonSearch(config),\n scavio_amazon_offers: scavioAmazonOffers(config),\n scavio_walmart_search: scavioWalmartSearch(config),\n scavio_tiktok_search: scavioTiktokSearch(config),\n scavio_instagram_search: scavioInstagramSearch(config),\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { tool } from \"ai\";\nimport { z } from \"zod\";\nimport { Scavio, type ScavioConfig, type GoogleSearchOptions } from \"scavio\";\n\nexport interface ScavioToolConfig extends ScavioConfig {\n /**\n * Max number of items to keep in the tool's result list. Defaults to 10.\n * Trimmed inside `data` on every platform except Google, whose body is flat.\n * Ignored by `scavioExtract`, which returns page content rather than a list.\n */\n maxResults?: number;\n /**\n * Add the five website tools (map, crawl, crawl status, batch extract, batch\n * status) to `scavioTools()`. Off by default: a crawl bills per page. The\n * individual factories (`scavioCrawlWebsite` and friends) work regardless.\n */\n enableCrawl?: boolean;\n /** Milliseconds between progress polls while a crawl or batch tool waits. Default 3000. */\n pollIntervalMs?: number;\n}\n\nfunction client(config?: ScavioToolConfig): Scavio {\n return new Scavio({ apiKey: config?.apiKey });\n}\n\n/**\n * Google is the ONLY family with a flat body: `organic_results` and friends sit\n * at the top level, next to `response_time` / `credits_used` / `credits_remaining`.\n */\nfunction trimFlat(res: Record<string, unknown>, key: string, max: number): Record<string, unknown> {\n const list = res[key];\n if (Array.isArray(list) && list.length > max) {\n return { ...res, [key]: list.slice(0, max) };\n }\n return res;\n}\n\n/**\n * Every non-Google endpoint nests its payload under `data` - the response is\n * `{ data: { products: [...] }, response_time, credits_used, credits_remaining }`.\n * Trimming the top level is therefore a silent no-op, so those tools trim\n * inside `data`.\n */\nfunction trimData(res: Record<string, unknown>, key: string, max: number): Record<string, unknown> {\n const data = res.data;\n if (!data || typeof data !== \"object\") return res;\n const list = (data as Record<string, unknown>)[key];\n if (Array.isArray(list) && list.length > max) {\n return { ...res, data: { ...(data as Record<string, unknown>), [key]: list.slice(0, max) } };\n }\n return res;\n}\n\n/**\n * Read any URL (/api/v1/extract).\n *\n * The one tool here that is not tied to a platform, and the only one `maxResults`\n * does not touch: extract returns page CONTENT, not a result list, so there is\n * nothing to trim and the body is returned whole. `extract` is a TOP-LEVEL\n * method on the SDK client - `c.extract({ url })`, never `c.extract.extract()`.\n *\n * Credits are a function of `mode`, not a per-call constant: \"normal\" 1,\n * \"advanced\" 1, \"ultra\" 2. Only a successful read is billed.\n */\nexport function scavioExtract(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Read any web page via the Scavio API and get it back as clean Markdown (default), plain text, or raw HTML. Use it on any URL, including one returned by the search tools. Returns `data.content` alongside `data.url`, `data.format`, `data.mode` and `data.content_length`. Cost depends on `mode`: 1 credit on 'normal' and 'advanced', 2 on 'ultra'; a dead link, bot wall or timeout is not billed.\",\n inputSchema: z.object({\n url: z\n .string()\n .describe(\n \"The page to read (1-2048 characters). http(s) only; a bare host is upgraded to https, and loopback, private, link-local and metadata hosts are rejected.\",\n ),\n format: z\n .enum([\"html\", \"markdown\", \"text\"])\n .optional()\n .describe(\n \"Output format (default 'markdown'): 'markdown' is a readability extraction with page chrome stripped, 'text' is that flattened to plain text, 'html' is the raw page.\",\n ),\n mode: z\n .enum([\"normal\", \"advanced\", \"ultra\"])\n .optional()\n .describe(\n \"Fetch tier, and the parameter that sets the price: 'normal' (default) is a plain fetch and costs 1 credit, 'advanced' renders JavaScript-built pages and costs 1, 'ultra' reaches the hardest pages and costs 2. Start on 'normal'.\",\n ),\n }),\n execute: async ({ url, format, mode }) => c.extract({ url, format, mode }),\n });\n}\n\n/** Google web search (/api/v2/google, 1 credit). */\nexport function scavioSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search the web with Google via the Scavio API (1 credit). Returns real-time organic search results, each with a title, link, and snippet, under `organic_results`.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n countryCode: z.string().optional().describe('Two-letter country code to localize results, e.g. \"us\".'),\n language: z.string().optional().describe('Two-letter UI language code, e.g. \"en\".'),\n page: z.number().int().optional().describe(\"1-based result page; page 2 starts at result 10.\"),\n device: z.enum([\"desktop\", \"mobile\"]).optional().describe(\"Device to emulate.\"),\n nfpr: z.boolean().optional().describe(\"Disable spelling auto-correction / similar-result substitution when true.\"),\n }),\n execute: async ({ query, countryCode, language, page, device, nfpr }) => {\n const params: GoogleSearchOptions = { query };\n if (countryCode) params.gl = countryCode;\n if (language) params.hl = language;\n if (page && page > 1) params.start = (page - 1) * 10;\n if (device) params.device = device;\n if (nfpr !== undefined) params.nfpr = nfpr;\n return trimFlat(await c.google.search(params), \"organic_results\", max);\n },\n });\n}\n\n/** YouTube video search (2 credits). */\nexport function scavioYoutubeSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search YouTube for videos, channels, or playlists via the Scavio API (2 credits). Videos come back under `data.results`, with `data.channels` and `data.playlists` alongside.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n upload_date: z.string().optional().describe(\"Upload date filter, e.g. 'today', 'this_week', 'this_month'.\"),\n type: z.string().optional().describe(\"Result type: 'video', 'channel', 'playlist', 'movie'.\"),\n duration: z.string().optional().describe(\"Duration filter: 'short', 'medium', 'long'.\"),\n sort_by: z.string().optional().describe(\"Sort order: 'relevance', 'date', 'view_count', 'rating'.\"),\n cursor: z.string().optional().describe(\"Pagination cursor (`next_cursor`) from a prior response.\"),\n }),\n execute: async ({ query, upload_date, type, duration, sort_by, cursor }) =>\n trimData(\n await c.youtube.search({ query, upload_date, type, duration, sort_by, cursor } as Parameters<\n typeof c.youtube.search\n >[0]),\n \"results\",\n max,\n ),\n });\n}\n\n/** YouTube video details (1 credit). */\nexport function scavioYoutubeVideo(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch full details for a YouTube video (title, author, view count, description, captions, chapters) via the Scavio API.\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n }),\n execute: async ({ video_id }) => c.youtube.video({ video_id }),\n });\n}\n\n/** YouTube video transcript / subtitles (8 credits). */\nexport function scavioYoutubeTranscript(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch a YouTube video's transcript or timed subtitles via the Scavio API (8 credits).\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n language: z.string().optional().describe(\"Transcript language code (default 'en').\"),\n format: z.enum([\"text\", \"srt\"]).optional().describe(\"'text' for a plain transcript, 'srt' for timed subtitles.\"),\n }),\n execute: async ({ video_id, language, format }) =>\n c.youtube.transcript({ video_id, language, format } as Parameters<typeof c.youtube.transcript>[0]),\n });\n}\n\n/** YouTube video comments (1 credit). */\nexport function scavioYoutubeComments(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description: \"List comments on a YouTube video via the Scavio API.\",\n inputSchema: z.object({\n video_id: z.string().describe(\"YouTube video id or a full watch URL.\"),\n cursor: z.string().optional().describe(\"Pagination cursor.\"),\n }),\n execute: async ({ video_id, cursor }) =>\n trimData(\n await c.youtube.comments({ video_id, cursor } as Parameters<typeof c.youtube.comments>[0]),\n \"comments\",\n max,\n ),\n });\n}\n\n/** YouTube channel details (1 credit). */\nexport function scavioYoutubeChannel(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Fetch a YouTube channel's details (subscribers, video count, views, links) via the Scavio API.\",\n inputSchema: z.object({\n channel_id: z.string().describe(\"YouTube channel id, @handle, or channel URL.\"),\n }),\n execute: async ({ channel_id }) => c.youtube.channel({ channel_id }),\n });\n}\n\n/**\n * Reddit post search (1 credit).\n *\n * The endpoint takes `query` and `cursor` and nothing else - it cannot sort or\n * filter by type, so no such input is offered. The API silently ignores those\n * params, which would leave a model believing it had filtered when it had not.\n */\nexport function scavioRedditSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Reddit posts via the Scavio API (1 credit). Returns matching posts under `data.results` with `data.next_cursor` for the next page. Results cannot be sorted or filtered by type.\",\n inputSchema: z.object({\n query: z.string().describe(\"The search query.\"),\n cursor: z.string().optional().describe(\"Pagination cursor (`next_cursor`) from a prior response.\"),\n }),\n execute: async ({ query, cursor }) => trimData(await c.reddit.search({ query, cursor }), \"results\", max),\n });\n}\n\n/**\n * Amazon product search.\n *\n * `domain` was dropped in favour of `country`, a two-letter marketplace code -\n * the upstream provider changed in 2026-07 and no longer takes a domain\n * suffix. It still works on the wire as a deprecated alias, but a model should\n * only ever see one spelling of a param.\n */\nexport function scavioAmazonSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Amazon for products via the Scavio API. Results are unsorted and cannot be filtered by category, merchant or price.\",\n inputSchema: z.object({\n query: z.string().describe(\"The product search query.\"),\n country: z\n .string()\n .optional()\n .describe(\n \"Marketplace country code (ISO 3166-1 alpha-2), not a domain: us (default), gb (the UK is gb, not uk), de, fr, jp, ... An unknown code falls back to us.\"\n ),\n }),\n execute: async ({ query, country }) =>\n trimData(await c.amazon.search({ query, country }), \"products\", max),\n });\n}\n\n/** Every seller offer for one Amazon ASIN. */\nexport function scavioAmazonOffers(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"List every seller offer for one Amazon ASIN via the Scavio API: price, seller, condition, shipping, and which offer holds the buy box. Page 1 only.\",\n inputSchema: z.object({\n asin: z.string().describe(\"Amazon Standard Identification Number (ASIN) of the product.\"),\n country: z\n .string()\n .optional()\n .describe(\n \"Marketplace country code (ISO 3166-1 alpha-2), not a domain: us (default), gb (the UK is gb, not uk), de, fr, jp, ... An unknown code falls back to us.\"\n ),\n }),\n execute: async ({ asin, country }) =>\n trimData(await c.amazon.offers({ asin, country }), \"offers\", max),\n });\n}\n\n/** Walmart product search. */\nexport function scavioWalmartSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description: \"Search Walmart for products via the Scavio API. Products come back under `data.products`.\",\n inputSchema: z.object({\n query: z.string().describe(\"The product search query.\"),\n }),\n execute: async ({ query }) => trimData(await c.walmart.search({ query }), \"products\", max),\n });\n}\n\n/** TikTok video search. */\nexport function scavioTiktokSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search TikTok for videos by keyword via the Scavio API. Videos come back under `data.aweme_list`.\",\n inputSchema: z.object({\n keyword: z.string().describe(\"The search keyword.\"),\n sort_type: z.enum([\"0\", \"1\"]).optional().describe(\"Sort order: '0' relevance, '1' most likes.\"),\n publish_time: z\n .enum([\"0\", \"1\", \"7\", \"30\", \"90\", \"180\"])\n .optional()\n .describe(\"Publish window in days: '0' all time, '1', '7', '30', '90', '180'.\"),\n }),\n execute: async ({ keyword, sort_type, publish_time }) =>\n trimData(\n await c.tiktok.searchVideos({\n keyword,\n sort_type,\n publish_time,\n } as Parameters<typeof c.tiktok.searchVideos>[0]),\n \"aweme_list\",\n max,\n ),\n });\n}\n\n/** Instagram user search. */\nexport function scavioInstagramSearch(config?: ScavioToolConfig) {\n const c = client(config);\n const max = config?.maxResults ?? 10;\n return tool({\n description:\n \"Search Instagram for users by keyword via the Scavio API (10 credits). Users come back under `data.users`.\",\n inputSchema: z.object({\n keyword: z.string().describe(\"The search keyword.\"),\n }),\n execute: async ({ keyword }) => trimData(await c.instagram.searchUsers({ keyword }), \"users\", max),\n });\n}\n\n// ---------------------------------------------------------------------------\n// Website map, crawl and batch: the multi-page members of the Extract family.\n//\n// Map answers in one call. Crawl and batch are background jobs: the start tools\n// post the job, then wait up to wait_seconds (default 45, max 300) for it to\n// finish, polling progress without page content, and return the job's status\n// with its first page of results either way. A job still running when the wait\n// ends keeps going server-side; read the rest with the matching status tool.\n// ---------------------------------------------------------------------------\n\nconst JOB_POLL_INTERVAL_MS = 3_000;\nconst JOB_WAIT_DEFAULT_SECONDS = 45;\nconst JOB_WAIT_MAX_SECONDS = 300;\nconst JOB_RESULTS_DEFAULT_LIMIT = 10;\nconst JOB_TERMINAL = new Set([\"completed\", \"failed\", \"cancelled\"]);\n\ntype JobQuery = {\n cursor?: string;\n limit?: number;\n status?: \"succeeded\" | \"failed\" | \"skipped\";\n include_content?: boolean;\n};\ntype JobPayload = { data?: { id?: string; status?: string } } & Record<string, unknown>;\ntype JobStatusFn = (id: string, query: JobQuery) => Promise<unknown>;\n\n// lib is ES2022 only (no DOM or Node types); every runtime this targets has setTimeout.\ndeclare const setTimeout: (callback: () => void, ms: number) => unknown;\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(() => resolve(), ms));\n\n/** Poll a job (content-free) until it finishes or the wait runs out, then read one results page. */\nasync function waitForJob(\n status: JobStatusFn,\n id: string,\n waitSeconds: number,\n pollMs: number,\n query: JobQuery,\n): Promise<Record<string, unknown>> {\n const deadline = Date.now() + Math.max(0, Math.min(waitSeconds, JOB_WAIT_MAX_SECONDS)) * 1000;\n for (;;) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n await sleep(Math.min(pollMs, remaining));\n const probe = (await status(id, { limit: 1, include_content: false })) as JobPayload;\n if (JOB_TERMINAL.has(String(probe?.data?.status))) break;\n }\n return (await status(id, query)) as Record<string, unknown>;\n}\n\n/** Start a job, then wait for it (bounded). wait_seconds 0 returns the 202 payload. */\nasync function startAndWait(\n start: () => Promise<unknown>,\n status: JobStatusFn,\n input: { wait_seconds?: number; limit?: number; include_content?: boolean },\n pollMs: number,\n): Promise<Record<string, unknown>> {\n const created = (await start()) as JobPayload;\n const id = created?.data?.id;\n const wait = input.wait_seconds ?? JOB_WAIT_DEFAULT_SECONDS;\n if (!id || wait <= 0) return created;\n const query: JobQuery = { limit: input.limit ?? JOB_RESULTS_DEFAULT_LIMIT };\n if (input.include_content !== undefined) query.include_content = input.include_content;\n return waitForJob(status, id, wait, pollMs, query);\n}\n\nconst MODE_DESCRIPTION =\n \"Fetch tier, and the parameter that sets the price: 'normal' (default) is the standard fetch, 'advanced' renders JavaScript-built pages, 'ultra' reaches the hardest pages.\";\nconst PATHS_DESCRIPTION =\n \"Path globs (max 20). '*' matches within one path segment, '**' across segments; a pattern without wildcards matches that path and everything under it. Example: ['/blog/**'].\";\nconst JOB_PRICE =\n \"Billed per SUCCESSFUL page at Extract's price for the mode: 'normal' and 'advanced' 1 credit, 'ultra' 2. Failed and skipped pages are free, and if the balance runs out the job stops cleanly.\";\n\nconst jobFields = {\n format: z.enum([\"html\", \"markdown\", \"text\"]).optional().describe(\"Format for each page, as on extract (default 'markdown').\"),\n mode: z.enum([\"normal\", \"advanced\", \"ultra\"]).optional().describe(MODE_DESCRIPTION),\n wait_seconds: z\n .number()\n .int()\n .min(0)\n .max(JOB_WAIT_MAX_SECONDS)\n .optional()\n .describe(\"Seconds to wait for the job to finish before returning, 0-300 (default 45). 0 returns the job id at once. A job still running when the wait ends keeps going; read it later with its status tool.\"),\n limit: z\n .number()\n .int()\n .min(1)\n .max(100)\n .optional()\n .describe(\"Results per response, 1-100 (default 10, to keep page content inside the context window); page on with next_cursor.\"),\n include_content: z.boolean().optional().describe(\"Set false to list results without their page content (default true).\"),\n};\n\nconst jobStatusSchema = z.object({\n id: z.string().describe(\"Job id returned when the job was started (data.id).\"),\n cursor: z.string().optional().describe(\"next_cursor from the previous response, to read the next page.\"),\n limit: jobFields.limit,\n status: z.enum([\"succeeded\", \"failed\", \"skipped\"]).optional().describe(\"Only results with this status.\"),\n include_content: jobFields.include_content,\n});\n\n/** Map a website's URLs (/api/v1/extract/map). 1 credit on 'normal'. */\nexport function scavioMapWebsite(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"List a website's page URLs via the Scavio API, gathered from its sitemaps and its start page, deduplicated, filtered by path or search words and limited: `data.links` [{ url, source, lastmod }], `data.total_found`, `data.truncated`. Pages the site's robots.txt disallows are left out. Use it to find the right pages before extracting or crawling. Costs 1 credit on 'normal'; up to 2 on 'advanced' and up to 10 on 'ultra', priced by what the call needed.\",\n inputSchema: z.object({\n url: z.string().describe(\"The site to map. A bare host is upgraded to https.\"),\n search: z.string().optional().describe(\"Only return URLs containing every word of this text (case-insensitive).\"),\n limit: z.number().int().min(1).max(5000).optional().describe(\"Maximum links to return, 1-5000. Default 1000 (or the plan's limit if lower: Free 500, PAYG 1,000, paid plans 5,000).\"),\n sitemap: z.enum([\"include\", \"only\", \"skip\"]).optional().describe(\"'include' combines the site's sitemaps with the start page's links (default); 'only' uses sitemaps alone; 'skip' uses page links alone.\"),\n include_subdomains: z.boolean().optional().describe(\"Also return URLs on subdomains of the site (default false).\"),\n include_paths: z.array(z.string()).optional().describe(\"Keep only URLs matching these. \" + PATHS_DESCRIPTION),\n exclude_paths: z.array(z.string()).optional().describe(\"Drop URLs matching these. \" + PATHS_DESCRIPTION),\n ignore_query_parameters: z.boolean().optional().describe(\"Treat URLs that differ only by query string as one URL (default true).\"),\n mode: jobFields.mode,\n }),\n execute: async (input) =>\n (await c.extract.map(input as Parameters<typeof c.extract.map>[0])) as unknown as Record<string, unknown>,\n });\n}\n\n/** Crawl a website (/api/v1/extract/crawl), then wait (bounded) for it. */\nexport function scavioCrawlWebsite(config?: ScavioToolConfig) {\n const c = client(config);\n const pollMs = config?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS;\n return tool({\n description:\n \"Crawl a website from one start URL via the Scavio API: same-site pages are discovered and extracted breadth-first within the page, depth and path limits, each returned as Markdown, text or HTML. Pages the site's robots.txt disallows are skipped. Waits up to wait_seconds (default 45) and returns `data` { id, status, pages, credits_used, results, next_cursor }; if status is still queued or running, call scavio_crawl_status with the id later. \" +\n JOB_PRICE,\n inputSchema: z.object({\n url: z.string().describe(\"Where the crawl starts. Only pages on the same site are crawled.\"),\n max_pages: z.number().int().min(1).max(10000).optional().describe(\"Maximum pages to fetch. Default 100. Plan limits: Free 10, PAYG 100, Project 500, Bootstrap 2,000, Startup 5,000, Growth 10,000.\"),\n max_depth: z.number().int().min(0).max(10).optional().describe(\"How many links away from the start page to follow, 0-10 (default 3). 0 fetches only the start page.\"),\n include_paths: z.array(z.string()).optional().describe(\"Crawl only paths matching these. \" + PATHS_DESCRIPTION),\n exclude_paths: z.array(z.string()).optional().describe(\"Skip paths matching these. \" + PATHS_DESCRIPTION),\n allow_subdomains: z.boolean().optional().describe(\"Also crawl subdomains of the site (default false).\"),\n ignore_query_parameters: z.boolean().optional().describe(\"Treat URLs that differ only by query string as one page (default true).\"),\n sitemap: z.enum([\"include\", \"skip\", \"only\"]).optional().describe(\"'include' also starts from the site's sitemap (default); 'skip' follows links only; 'only' fetches sitemap pages without following links.\"),\n ...jobFields,\n }),\n execute: async (input) => {\n const { wait_seconds, limit, include_content, ...body } = input;\n return startAndWait(\n () => c.extract.crawl(body as Parameters<typeof c.extract.crawl>[0]),\n (id, q) => c.extract.crawlStatus(id, q),\n { wait_seconds, limit, include_content },\n pollMs,\n );\n },\n });\n}\n\n/** A crawl's progress and page results (GET /api/v1/extract/crawl/{id}). Free. */\nexport function scavioCrawlStatus(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Read a crawl's progress and its page results by job id via the Scavio API, paged by cursor: `data` { status, stopped_reason, pages, credits_used, results: [{ url, status, content }], next_cursor }. Results are kept for 3 days after the crawl finishes. Free: reading a job costs 0 credits.\",\n inputSchema: jobStatusSchema,\n execute: async ({ id, limit, ...q }) =>\n (await c.extract.crawlStatus(id, { ...q, limit: limit ?? JOB_RESULTS_DEFAULT_LIMIT })) as unknown as Record<string, unknown>,\n });\n}\n\n/** Extract a list of URLs in one job (/api/v1/extract/batch), then wait (bounded). */\nexport function scavioBatchExtract(config?: ScavioToolConfig) {\n const c = client(config);\n const pollMs = config?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS;\n return tool({\n description:\n \"Extract a list of URLs (up to 1,000, plan-limited) in one job via the Scavio API, each returned as Markdown, text or HTML exactly like scavio_extract. Waits up to wait_seconds (default 45) and returns `data` { id, status, pages, credits_used, results, next_cursor }; if status is still queued or running, call scavio_batch_status with the id later. \" +\n JOB_PRICE,\n inputSchema: z.object({\n urls: z.array(z.string()).min(1).max(1000).describe(\"The pages to extract (duplicates removed). Plan limits: Free 10, PAYG 50, Project 100, Bootstrap 500, Startup and Growth 1,000.\"),\n ...jobFields,\n }),\n execute: async (input) => {\n const { wait_seconds, limit, include_content, ...body } = input;\n return startAndWait(\n () => c.extract.batch(body as Parameters<typeof c.extract.batch>[0]),\n (id, q) => c.extract.batchStatus(id, q),\n { wait_seconds, limit, include_content },\n pollMs,\n );\n },\n });\n}\n\n/** A batch's progress and page results (GET /api/v1/extract/batch/{id}). Free. */\nexport function scavioBatchStatus(config?: ScavioToolConfig) {\n const c = client(config);\n return tool({\n description:\n \"Read a batch extract's progress and its page results by job id via the Scavio API, paged by cursor: `data` { status, pages, credits_used, results: [{ url, status, content }], next_cursor }. Results are kept for 3 days after the batch finishes. Free: reading a job costs 0 credits.\",\n inputSchema: jobStatusSchema,\n execute: async ({ id, limit, ...q }) =>\n (await c.extract.batchStatus(id, { ...q, limit: limit ?? JOB_RESULTS_DEFAULT_LIMIT })) as unknown as Record<string, unknown>,\n });\n}\n\n/**\n * All Scavio tools as an object keyed by tool name, ready to spread into the\n * `tools` option of `generateText` / `streamText`.\n */\nexport function scavioTools(config?: ScavioToolConfig) {\n return {\n scavio_extract: scavioExtract(config),\n scavio_search: scavioSearch(config),\n scavio_youtube_search: scavioYoutubeSearch(config),\n scavio_youtube_video: scavioYoutubeVideo(config),\n scavio_youtube_transcript: scavioYoutubeTranscript(config),\n scavio_youtube_comments: scavioYoutubeComments(config),\n scavio_youtube_channel: scavioYoutubeChannel(config),\n scavio_reddit_search: scavioRedditSearch(config),\n scavio_amazon_search: scavioAmazonSearch(config),\n scavio_amazon_offers: scavioAmazonOffers(config),\n scavio_walmart_search: scavioWalmartSearch(config),\n scavio_tiktok_search: scavioTiktokSearch(config),\n scavio_instagram_search: scavioInstagramSearch(config),\n ...(config?.enableCrawl\n ? {\n scavio_map_website: scavioMapWebsite(config),\n scavio_crawl_website: scavioCrawlWebsite(config),\n scavio_crawl_status: scavioCrawlStatus(config),\n scavio_batch_extract: scavioBatchExtract(config),\n scavio_batch_status: scavioBatchStatus(config),\n }\n : {}),\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@scavio/ai-sdk",
3
- "version": "0.3.0",
4
- "description": "Scavio search tools for the Vercel AI SDK (Google, YouTube, Reddit, Amazon, Walmart, TikTok, Instagram).",
3
+ "version": "0.5.0",
4
+ "description": "Scavio search, URL-extraction and website crawl tools for the Vercel AI SDK (extract any URL, map, crawl and batch-extract sites, plus Google, YouTube, Reddit, Amazon, Walmart, TikTok, Instagram).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",
@@ -32,6 +32,11 @@
32
32
  "vercel-ai-sdk",
33
33
  "tools",
34
34
  "search",
35
+ "extract",
36
+ "web-crawler",
37
+ "website-crawler",
38
+ "sitemap",
39
+ "web-scraping",
35
40
  "agents"
36
41
  ],
37
42
  "license": "MIT",
@@ -48,12 +53,12 @@
48
53
  "zod": ">=3"
49
54
  },
50
55
  "dependencies": {
51
- "scavio": "^0.13.0"
56
+ "scavio": "^0.23.0"
52
57
  },
53
58
  "devDependencies": {
54
59
  "@ai-sdk/openai": "^3.0.74",
55
60
  "ai": "^6.0.208",
56
- "scavio": "^0.13.0",
61
+ "scavio": "^0.23.0",
57
62
  "tsup": "^8.0.0",
58
63
  "typescript": "^5.4.0",
59
64
  "vitest": "^2.0.0",