diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7a48e52..d18e944 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.12.0" + ".": "2.13.0" } diff --git a/.stats.yml b/.stats.yml index 9673209..4aa99bd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 41 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-b0c72d2fe5911c9ce155275b954198bf2152e915a7e5b9f719aad50e222b9ef8.yml -openapi_spec_hash: 5cf943ea5718059b7975417b012cee28 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-bf7ffa610bd4a02ea5bcb157521d17a041a48f78d87bf8fe8d812d3cbb87b489.yml +openapi_spec_hash: 90142d96969dea44c46a01abb683c426 config_hash: 0fb0ceca5946298c416cec0cca5260c7 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3323f5b..a750c60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 2.13.0 (2026-08-21) + +Full Changelog: [v2.12.0...v2.13.0](https://github.com/context-dot-dev/context-typescript-sdk/compare/v2.12.0...v2.13.0) + +### Features + +* **api:** api update ([f5eb318](https://github.com/context-dot-dev/context-typescript-sdk/commit/f5eb318e838c4f1fd12b5c4655ac611845b7cdc7)) +* **api:** api update ([ffd01d5](https://github.com/context-dot-dev/context-typescript-sdk/commit/ffd01d589e8b1aefcc9898d3106293e8e1dbc7ac)) +* **api:** api update ([b1101a1](https://github.com/context-dot-dev/context-typescript-sdk/commit/b1101a1dbe73834cd33fd721a28158822128c92a)) + ## 2.12.0 (2026-08-18) Full Changelog: [v2.11.0...v2.12.0](https://github.com/context-dot-dev/context-typescript-sdk/compare/v2.11.0...v2.12.0) diff --git a/package.json b/package.json index 3e19a47..8a97350 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "context.dev", - "version": "2.12.0", + "version": "2.13.0", "description": "The official TypeScript library for the Context Dev API", "author": "Context Dev ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json index 2610ab1..a82d684 100644 --- a/packages/mcp-server/manifest.json +++ b/packages/mcp-server/manifest.json @@ -1,7 +1,7 @@ { "dxt_version": "0.2", "name": "context.dev-mcp", - "version": "2.12.0", + "version": "2.13.0", "description": "The official MCP Server for the Context Dev API", "author": { "name": "Context Dev", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index b05741a..7383e59 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "context.dev-mcp", - "version": "2.12.0", + "version": "2.13.0", "description": "The official MCP Server for the Context Dev API", "author": "Context Dev ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index a2908cc..fb0f792 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -470,7 +470,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: '{ metadata: { maxCrawlDepth: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; }; results: { markdown: string; metadata: { crawlDepth: number; finalUrl: string; sourceUrl: string; statusCode: number; success: boolean; title: string; url: string; additionalMeta?: object; alternates?: object[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; headings?: object[]; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; twitter?: object; }; }[]; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }', markdown: - '## web_crawl_md\n\n`client.web.webCrawlMd(url: string, country?: string, excludeSelectors?: string[], followSubdomains?: boolean, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, includeSelectors?: string[], maxAgeMs?: number, maxDepth?: number, maxPages?: number, pdf?: { end?: number; ocr?: boolean; shouldParse?: boolean; start?: number; }, settleAnimations?: boolean, shortenBase64Images?: boolean, stopAfterMs?: number, tags?: string[], timeoutMS?: number, urlRegex?: string, useMainContentOnly?: boolean, waitForMs?: number, zdr?: \'enabled\' | \'disabled\'): { metadata: object; results: object[]; key_metadata?: object; }`\n\n**post** `/web/crawl`\n\nPerforms a crawl starting from a given URL, extracts page content as Markdown, and returns results for all crawled pages.\n\n### Parameters\n\n- `url: string`\n The starting URL for the crawl (must include http:// or https:// protocol)\n\n- `country?: string`\n Fetch the target page through a residential proxy in this country (ISO 3166-1 alpha-2).\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove before each crawled page is converted to Markdown. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]".\n\n- `followSubdomains?: boolean`\n When true, follow links on subdomains of the starting URL\'s domain (e.g. docs.example.com when starting from example.com). www and apex are always treated as equivalent.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown for each crawled page.\n\n- `includeImages?: boolean`\n Include image references in the Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in the Markdown output\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching HTML subtrees (and their descendants) are kept before each crawled page is converted to Markdown. When omitted, the entire document is kept. Examples: "article.main", "#content", "[role=main]".\n\n- `maxAgeMs?: number`\n Return a cached result if a prior scrape for the same parameters exists and is younger than this many milliseconds. Defaults to 1 day (86400000 ms) when omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh.\n\n- `maxDepth?: number`\n Maximum link depth from the starting URL (0 = only the starting page)\n\n- `maxPages?: number`\n Maximum number of pages to crawl. Hard cap: 500.\n\n- `pdf?: { end?: number; ocr?: boolean; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and embedded-image detection/OCR to an inclusive 1-based page range.\n - `end?: number`\n Last 1-based PDF page to parse. When omitted, parsing ends at the last page. Must be greater than or equal to start when both are provided.\n - `ocr?: boolean`\n When true, OCR the selected PDF pages that have no usable text layer (scans), replacing each recovered page\'s text with the OCR result while pages with a real text layer keep it. Billed at 1 credit per page OCR actually recovered, on top of the base request cost.\n - `shouldParse?: boolean`\n When true, PDF pages are fetched and parsed. When false, PDF pages are skipped entirely (not included in results and not counted as failures).\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `settleAnimations?: boolean`\n When true, waits briefly for CSS and transition animations to settle before extracting each crawled page. Defaults to false. This adds a bit of latency in exchange for more stable output on animated pages.\n\n- `shortenBase64Images?: boolean`\n Truncate base64-encoded image data in the Markdown output\n\n- `stopAfterMs?: number`\n Soft time budget for the crawl in milliseconds. After each scrape, the crawler checks the elapsed time and, if exceeded, returns the pages collected so far instead of continuing. Min: 10000 (10s). Max: 110000 (110s). Default: 80000 (80s).\n\n- `tags?: string[]`\n Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes).\n\n- `urlRegex?: string`\n Regex pattern. Only URLs matching this pattern will be followed and scraped.\n\n- `useMainContentOnly?: boolean`\n Extract only the main content, stripping headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load for each crawled page. Min: 0. Max: 30000 (30 seconds). \n\n- `zdr?: \'enabled\' | \'disabled\'`\n Set to enabled to bypass shared caches and omit request and response content from retained usage logs. Requires zero data retention to be enabled for your organization (contact support@context.dev), otherwise the request fails with ZDR_NOT_ENABLED. Successful ZDR responses include X-Context-ZDR: true.\n\n### Returns\n\n- `{ metadata: { maxCrawlDepth: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; }; results: { markdown: string; metadata: { crawlDepth: number; finalUrl: string; sourceUrl: string; statusCode: number; success: boolean; title: string; url: string; additionalMeta?: object; alternates?: object[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; headings?: object[]; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; twitter?: object; }; }[]; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `metadata: { maxCrawlDepth: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; }`\n - `results: { markdown: string; metadata: { crawlDepth: number; finalUrl: string; sourceUrl: string; statusCode: number; success: boolean; title: string; url: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; headings?: { level: number; text: string; }[]; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; twitter?: object; }; }[]`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport ContextDev from \'context.dev\';\n\nconst client = new ContextDev();\n\nconst response = await client.web.webCrawlMd({ url: \'https://example.com\' });\n\nconsole.log(response);\n```', + '## web_crawl_md\n\n`client.web.webCrawlMd(url: string, country?: string, excludeSelectors?: string[], followSubdomains?: boolean, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, includeSelectors?: string[], maxAgeMs?: number, maxDepth?: number, maxPages?: number, pdf?: { end?: number; ocr?: boolean; shouldParse?: boolean; start?: number; }, settleAnimations?: boolean, shortenBase64Images?: boolean, stopAfterMs?: number, tags?: string[], timeoutMS?: number, urlRegex?: string, useMainContentOnly?: boolean, waitForMs?: number, zdr?: \'enabled\' | \'disabled\'): { metadata: object; results: object[]; key_metadata?: object; }`\n\n**post** `/web/crawl`\n\nPerforms a crawl starting from a given URL, extracts page content as Markdown, and returns results for all crawled pages.\n\n### Parameters\n\n- `url: string`\n The starting URL for the crawl (must include http:// or https:// protocol)\n\n- `country?: string`\n Fetch the target page through a residential proxy in this country (ISO 3166-1 alpha-2).\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove before each crawled page is converted to Markdown. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]".\n\n- `followSubdomains?: boolean`\n When true, follow links on subdomains of the starting URL\'s domain (e.g. docs.example.com when starting from example.com). www and apex are always treated as equivalent.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown for each crawled page.\n\n- `includeImages?: boolean`\n Include image references in the Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in the Markdown output\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching HTML subtrees (and their descendants) are kept before each crawled page is converted to Markdown. When omitted, the entire document is kept. Examples: "article.main", "#content", "[role=main]".\n\n- `maxAgeMs?: number`\n Return a cached result if a prior scrape for the same parameters exists and is younger than this many milliseconds. Defaults to 1 day (86400000 ms) when omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh.\n\n- `maxDepth?: number`\n Maximum link depth from the starting URL (0 = only the starting page)\n\n- `maxPages?: number`\n Maximum number of pages to crawl. Hard cap: 500.\n\n- `pdf?: { end?: number; ocr?: boolean; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and embedded-image detection/OCR to an inclusive 1-based page range.\n - `end?: number`\n Last 1-based PDF page to parse. When omitted, parsing ends at the last page. Must be greater than or equal to start when both are provided.\n - `ocr?: boolean`\n When true, OCR the selected PDF pages that have no usable text layer (scans), replacing each recovered page\'s text with the OCR result while pages with a real text layer keep it. Billed at 1 credit per page OCR actually recovered, on top of the base request cost.\n - `shouldParse?: boolean`\n When true, PDF pages are fetched and parsed. When false, PDF pages are skipped entirely (not included in results and not counted as failures).\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `settleAnimations?: boolean`\n When true, waits briefly for CSS and transition animations to settle before extracting each crawled page. Defaults to false. This adds a bit of latency in exchange for more stable output on animated pages.\n\n- `shortenBase64Images?: boolean`\n Truncate base64-encoded image data in the Markdown output\n\n- `stopAfterMs?: number`\n Soft time budget for the crawl in milliseconds. After each scrape, the crawler checks the elapsed time and, if exceeded, returns the pages collected so far instead of continuing. Min: 10000 (10s). Max: 110000 (110s). Default: 80000 (80s).\n\n- `tags?: string[]`\n Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes).\n\n- `urlRegex?: string`\n Regex pattern. Only URLs matching this pattern will be followed and scraped. An automatic prefix scope in the form ^ follows a redirect of the starting page.\n\n- `useMainContentOnly?: boolean`\n Extract only the main content, stripping headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Browser wait time in milliseconds after initial page load for each crawled page. Defaults to 3500 (3.5 seconds). Min: 0. Max: 30000 (30 seconds).\n\n- `zdr?: \'enabled\' | \'disabled\'`\n Set to enabled to bypass shared caches and omit request and response content from retained usage logs. Requires zero data retention to be enabled for your organization (contact support@context.dev), otherwise the request fails with ZDR_NOT_ENABLED. Successful ZDR responses include X-Context-ZDR: true.\n\n### Returns\n\n- `{ metadata: { maxCrawlDepth: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; }; results: { markdown: string; metadata: { crawlDepth: number; finalUrl: string; sourceUrl: string; statusCode: number; success: boolean; title: string; url: string; additionalMeta?: object; alternates?: object[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; headings?: object[]; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; twitter?: object; }; }[]; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `metadata: { maxCrawlDepth: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; }`\n - `results: { markdown: string; metadata: { crawlDepth: number; finalUrl: string; sourceUrl: string; statusCode: number; success: boolean; title: string; url: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; headings?: { level: number; text: string; }[]; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; twitter?: object; }; }[]`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport ContextDev from \'context.dev\';\n\nconst client = new ContextDev();\n\nconst response = await client.web.webCrawlMd({ url: \'https://example.com\' });\n\nconsole.log(response);\n```', perLanguage: { typescript: { method: 'client.web.webCrawlMd', @@ -692,6 +692,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ params: [ 'schema: object;', 'url: string;', + "actions?: { do: 'wait'; timeMs: number; } | { action: string; do: 'perform'; }[];", 'factCheck?: boolean;', 'followSubdomains?: boolean;', 'includeFrames?: boolean;', @@ -707,9 +708,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'waitForMs?: number;', ], response: - '{ data: object; metadata: { maxCrawlDepth: number; numBlocked: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; }; status: string; url: string; urls_analyzed: string[]; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }', + "{ data: object; metadata: { maxCrawlDepth: number; numBlocked: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; actionsApplied?: { instruction: string; status: 'applied' | 'failed' | 'skipped'; completionEvidence?: string; durationMs?: number; error?: string; method?: string; targetDescription?: string; }[]; }; status: string; url: string; urls_analyzed: string[]; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", markdown: - "## extract\n\n`client.web.extract(schema: object, url: string, factCheck?: boolean, followSubdomains?: boolean, includeFrames?: boolean, instructions?: string, maxAgeMs?: number, maxDepth?: number, maxPages?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, settleAnimations?: boolean, stopAfterMs?: number, tags?: string[], timeoutMS?: number, waitForMs?: number): { data: object; metadata: object; status: string; url: string; urls_analyzed: string[]; key_metadata?: object; }`\n\n**post** `/web/extract`\n\nCrawl a website, use the provided JSON Schema and instructions to prioritize relevant internal links, and extract structured data from the selected pages.\n\n### Parameters\n\n- `schema: object`\n JSON Schema for the returned data object. TypeScript Zod users can pass a JSON Schema generated from a Zod object; Python users can pass the equivalent JSON Schema object.\n\n- `url: string`\n The starting website URL to crawl and extract from. Must include http:// or https://.\n\n- `factCheck?: boolean`\n When true, every returned value must be grounded in facts stated on the page; fields that cannot be supported by the page are returned as null/empty. When false (default), the model may make reasonable inferences and derivations from the page content (e.g. ideal customer, competitor analysis, recommendations) while keeping verifiable specifics (names, quotes, URLs, dates, metrics) faithful to the source.\n\n- `followSubdomains?: boolean`\n When true, follow links on subdomains of the starting URL's domain.\n\n- `includeFrames?: boolean`\n When true, iframe contents are included in Markdown before extraction.\n\n- `instructions?: string`\n Optional extraction guidance, such as which facts to prioritize or how to interpret fields in the schema.\n\n- `maxAgeMs?: number`\n Return cached scrape results if a prior scrape for the same parameters is younger than this many milliseconds. Defaults to 7 days (604800000 ms).\n\n- `maxDepth?: number`\n Optional maximum link depth from the starting URL (0 = only the starting page). If omitted, there is no crawl depth limit.\n\n- `maxPages?: number`\n Maximum number of pages to analyze for extraction. Hard cap: 50. Defaults to 5.\n\n- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n - `end?: number`\n Last 1-based PDF page to parse. Must be greater than or equal to start when both are provided.\n - `shouldParse?: boolean`\n When true, PDF pages are fetched and parsed. When false, PDF pages are skipped.\n - `start?: number`\n First 1-based PDF page to parse.\n\n- `settleAnimations?: boolean`\n When true, waits briefly for CSS and transition animations to settle before extracting each crawled page. Defaults to false. This adds a bit of latency in exchange for more stable output on animated pages.\n\n- `stopAfterMs?: number`\n Soft time budget for the crawl in milliseconds. Min: 10000 (10s). Max: 110000 (110s). Default: 80000 (80s).\n\n- `tags?: string[]`\n Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes).\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load for each crawled page.\n\n### Returns\n\n- `{ data: object; metadata: { maxCrawlDepth: number; numBlocked: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; }; status: string; url: string; urls_analyzed: string[]; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `data: object`\n - `metadata: { maxCrawlDepth: number; numBlocked: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; }`\n - `status: string`\n - `url: string`\n - `urls_analyzed: string[]`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst response = await client.web.extract({\n schema: {\n type: 'bar',\n properties: 'bar',\n required: 'bar',\n additionalProperties: 'bar',\n},\n url: 'https://example.com',\n});\n\nconsole.log(response);\n```", + "## extract\n\n`client.web.extract(schema: object, url: string, actions?: { do: 'wait'; timeMs: number; } | { action: string; do: 'perform'; }[], factCheck?: boolean, followSubdomains?: boolean, includeFrames?: boolean, instructions?: string, maxAgeMs?: number, maxDepth?: number, maxPages?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, settleAnimations?: boolean, stopAfterMs?: number, tags?: string[], timeoutMS?: number, waitForMs?: number): { data: object; metadata: object; status: string; url: string; urls_analyzed: string[]; key_metadata?: object; }`\n\n**post** `/web/extract`\n\nCrawl a website, use the provided JSON Schema and instructions to prioritize relevant internal links, and extract structured data from the selected pages.\n\n### Parameters\n\n- `schema: object`\n JSON Schema for the returned data object. Image fields such as `image_urls` or `product_photos` automatically make page image references available to extraction, so product data and photos can be returned in one call. TypeScript Zod users can pass a JSON Schema generated from a Zod object; Python users can pass the equivalent JSON Schema object.\n\n- `url: string`\n The starting website URL to crawl and extract from. Must include http:// or https://.\n\n- `actions?: { do: 'wait'; timeMs: number; } | { action: string; do: 'perform'; }[]`\n Optional browser actions executed in order on the requested page after it loads and before extraction. Requires a paid plan. When actions are provided and stopAfterMs is omitted, the crawl budget defaults to 110000 ms.\n\n- `factCheck?: boolean`\n When true, every returned value must be grounded in facts stated on the page; fields that cannot be supported by the page are returned as null/empty. When false (default), the model may make reasonable inferences and derivations from the page content (e.g. ideal customer, competitor analysis, recommendations) while keeping verifiable specifics (names, quotes, URLs, dates, metrics) faithful to the source.\n\n- `followSubdomains?: boolean`\n When true, follow links on subdomains of the starting URL's domain.\n\n- `includeFrames?: boolean`\n When true, iframe contents are included in Markdown before extraction.\n\n- `instructions?: string`\n Optional extraction guidance, such as which facts to prioritize or how to interpret fields in the schema.\n\n- `maxAgeMs?: number`\n Return cached scrape results if a prior scrape for the same parameters is younger than this many milliseconds. Defaults to 7 days (604800000 ms).\n\n- `maxDepth?: number`\n Optional maximum link depth from the starting URL (0 = only the starting page). If omitted, there is no crawl depth limit.\n\n- `maxPages?: number`\n Maximum number of pages to analyze for extraction. Hard cap: 50. Defaults to 5.\n\n- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n - `end?: number`\n Last 1-based PDF page to parse. Must be greater than or equal to start when both are provided.\n - `shouldParse?: boolean`\n When true, PDF pages are fetched and parsed. When false, PDF pages are skipped.\n - `start?: number`\n First 1-based PDF page to parse.\n\n- `settleAnimations?: boolean`\n When true, waits briefly for CSS and transition animations to settle before extracting each crawled page. Defaults to false. This adds a bit of latency in exchange for more stable output on animated pages.\n\n- `stopAfterMs?: number`\n Soft time budget for the crawl in milliseconds. Min: 10000 (10s). Max: 110000 (110s). Defaults to 80000 (80s), or 110000 (110s) when browser actions are provided.\n\n- `tags?: string[]`\n Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes).\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load for each crawled page.\n\n### Returns\n\n- `{ data: object; metadata: { maxCrawlDepth: number; numBlocked: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; actionsApplied?: { instruction: string; status: 'applied' | 'failed' | 'skipped'; completionEvidence?: string; durationMs?: number; error?: string; method?: string; targetDescription?: string; }[]; }; status: string; url: string; urls_analyzed: string[]; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `data: object`\n - `metadata: { maxCrawlDepth: number; numBlocked: number; numFailed: number; numSkipped: number; numSucceeded: number; numUrls: number; actionsApplied?: { instruction: string; status: 'applied' | 'failed' | 'skipped'; completionEvidence?: string; durationMs?: number; error?: string; method?: string; targetDescription?: string; }[]; }`\n - `status: string`\n - `url: string`\n - `urls_analyzed: string[]`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst response = await client.web.extract({\n schema: {\n type: 'bar',\n properties: 'bar',\n required: 'bar',\n additionalProperties: 'bar',\n},\n url: 'https://example.com',\n});\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.web.extract', @@ -739,7 +740,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ php: { method: 'web->extract', example: - "web->extract(\n schema: [\n 'type' => 'bar',\n 'properties' => 'bar',\n 'required' => 'bar',\n 'additionalProperties' => 'bar',\n ],\n url: 'https://example.com',\n factCheck: true,\n followSubdomains: true,\n includeFrames: true,\n instructions: 'instructions',\n maxAgeMs: 0,\n maxDepth: 0,\n maxPages: 1,\n pdf: ['end' => 1, 'shouldParse' => true, 'start' => 1],\n settleAnimations: true,\n stopAfterMs: 10000,\n tags: ['production', 'team-alpha'],\n timeoutMs: 1000,\n waitForMs: 0,\n);\n\nvar_dump($response);", + "web->extract(\n schema: [\n 'type' => 'bar',\n 'properties' => 'bar',\n 'required' => 'bar',\n 'additionalProperties' => 'bar',\n ],\n url: 'https://example.com',\n actions: [['do' => 'wait', 'timeMs' => 0]],\n factCheck: true,\n followSubdomains: true,\n includeFrames: true,\n instructions: 'instructions',\n maxAgeMs: 0,\n maxDepth: 0,\n maxPages: 1,\n pdf: ['end' => 1, 'shouldParse' => true, 'start' => 1],\n settleAnimations: true,\n stopAfterMs: 10000,\n tags: ['production', 'team-alpha'],\n timeoutMs: 1000,\n waitForMs: 0,\n);\n\nvar_dump($response);", }, http: { example: @@ -810,7 +811,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ '{ domain: string; maxAgeMs?: number; maxProducts?: number; tags?: string[]; timeoutMS?: number; } | { directUrl: string; maxAgeMs?: number; maxProducts?: number; tags?: string[]; timeoutMS?: number; };', ], response: - "{ key_metadata?: { credits_consumed: number; credits_remaining: number; }; products?: { description: string; features: string[]; images: string[]; name: string; sku: string; tags: string[]; target_audience: string[]; billing_frequency?: 'monthly' | 'yearly' | 'one_time' | 'usage_based'; category?: string; currency?: string; image_url?: string; price?: number; pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom'; url?: string; }[]; }", + "{ key_metadata?: { credits_consumed: number; credits_remaining: number; }; products?: { description: string; features: string[]; images: string[]; name: string; sku: string; tags: string[]; target_audience: string[]; availability?: string; billing_frequency?: 'monthly' | 'yearly' | 'one_time' | 'usage_based'; category?: string; currency?: string; dimensions?: string[]; image_url?: string; price?: number; pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom'; regular_price?: number; url?: string; }[]; }", perLanguage: { typescript: { method: 'client.ai.extractProducts', @@ -859,9 +860,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.ai.extractProduct', params: ['url: string;', 'maxAgeMs?: number;', 'tags?: string[];', 'timeoutMS?: number;'], response: - "{ is_product_page?: boolean; key_metadata?: { credits_consumed: number; credits_remaining: number; }; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: { description: string; features: string[]; images: string[]; name: string; sku: string; tags: string[]; target_audience: string[]; billing_frequency?: 'monthly' | 'yearly' | 'one_time' | 'usage_based'; category?: string; currency?: string; image_url?: string; price?: number; pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom'; url?: string; }; }", + "{ is_product_page?: boolean; key_metadata?: { credits_consumed: number; credits_remaining: number; }; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: { description: string; features: string[]; images: string[]; name: string; sku: string; tags: string[]; target_audience: string[]; availability?: string; billing_frequency?: 'monthly' | 'yearly' | 'one_time' | 'usage_based'; category?: string; currency?: string; dimensions?: string[]; image_url?: string; price?: number; pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom'; regular_price?: number; url?: string; }; }", markdown: - "## extract_product\n\n`client.ai.extractProduct(url: string, maxAgeMs?: number, tags?: string[], timeoutMS?: number): { is_product_page?: boolean; key_metadata?: object; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: object; }`\n\n**post** `/brand/ai/product`\n\nGiven a single URL, determines if it is a product page and extracts the product information.\n\n### Parameters\n\n- `url: string`\n The product page URL to extract product data from.\n\n- `maxAgeMs?: number`\n Return a cached result if a prior scrape for the same parameters exists and is younger than this many milliseconds. Defaults to 7 days (604800000 ms) when omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh.\n\n- `tags?: string[]`\n Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; key_metadata?: { credits_consumed: number; credits_remaining: number; }; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: { description: string; features: string[]; images: string[]; name: string; sku: string; tags: string[]; target_audience: string[]; billing_frequency?: 'monthly' | 'yearly' | 'one_time' | 'usage_based'; category?: string; currency?: string; image_url?: string; price?: number; pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom'; url?: string; }; }`\n\n - `is_product_page?: boolean`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'`\n - `product?: { description: string; features: string[]; images: string[]; name: string; sku: string; tags: string[]; target_audience: string[]; billing_frequency?: 'monthly' | 'yearly' | 'one_time' | 'usage_based'; category?: string; currency?: string; image_url?: string; price?: number; pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom'; url?: string; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst response = await client.ai.extractProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## extract_product\n\n`client.ai.extractProduct(url: string, maxAgeMs?: number, tags?: string[], timeoutMS?: number): { is_product_page?: boolean; key_metadata?: object; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: object; }`\n\n**post** `/brand/ai/product`\n\nGiven a single URL, determines if it is a product page and extracts the product information.\n\n### Parameters\n\n- `url: string`\n The product page URL to extract product data from.\n\n- `maxAgeMs?: number`\n Return a cached result if a prior scrape for the same parameters exists and is younger than this many milliseconds. Defaults to 7 days (604800000 ms) when omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh.\n\n- `tags?: string[]`\n Optional tags for tracking usage. Up to 20 tags, each 1 to 50 characters.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. If the request takes longer than this value, it will be aborted with a 408 status code. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; key_metadata?: { credits_consumed: number; credits_remaining: number; }; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: { description: string; features: string[]; images: string[]; name: string; sku: string; tags: string[]; target_audience: string[]; availability?: string; billing_frequency?: 'monthly' | 'yearly' | 'one_time' | 'usage_based'; category?: string; currency?: string; dimensions?: string[]; image_url?: string; price?: number; pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom'; regular_price?: number; url?: string; }; }`\n\n - `is_product_page?: boolean`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'`\n - `product?: { description: string; features: string[]; images: string[]; name: string; sku: string; tags: string[]; target_audience: string[]; availability?: string; billing_frequency?: 'monthly' | 'yearly' | 'one_time' | 'usage_based'; category?: string; currency?: string; dimensions?: string[]; image_url?: string; price?: number; pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom'; regular_price?: number; url?: string; }`\n\n### Example\n\n```typescript\nimport ContextDev from 'context.dev';\n\nconst client = new ContextDev();\n\nconst response = await client.ai.extractProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.ai.extractProduct', diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 639b971..60552af 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -28,7 +28,7 @@ export const newMcpServer = async ({ new McpServer( { name: 'context_dev_api', - version: '2.12.0', + version: '2.13.0', }, { instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }), diff --git a/src/resources/ai.ts b/src/resources/ai.ts index f8d03b1..b2744ef 100644 --- a/src/resources/ai.ts +++ b/src/resources/ai.ts @@ -122,6 +122,19 @@ export namespace AIExtractProductResponse { */ target_audience: Array; + /** + * Normalized stock or ordering availability + */ + availability?: + | 'in_stock' + | 'out_of_stock' + | 'limited_availability' + | 'preorder' + | 'backorder' + | 'made_to_order' + | 'discontinued' + | null; + /** * Billing frequency for the product */ @@ -137,6 +150,11 @@ export namespace AIExtractProductResponse { */ currency?: string | null; + /** + * Dimension statements shown for the product, preserving labels, values, and units + */ + dimensions?: Array; + /** * URL to the product image */ @@ -152,6 +170,11 @@ export namespace AIExtractProductResponse { */ pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom' | null; + /** + * Original or regular price before a displayed discount + */ + regular_price?: number | null; + /** * URL to the product page */ @@ -225,6 +248,19 @@ export namespace AIExtractProductsResponse { */ target_audience: Array; + /** + * Normalized stock or ordering availability + */ + availability?: + | 'in_stock' + | 'out_of_stock' + | 'limited_availability' + | 'preorder' + | 'backorder' + | 'made_to_order' + | 'discontinued' + | null; + /** * Billing frequency for the product */ @@ -240,6 +276,11 @@ export namespace AIExtractProductsResponse { */ currency?: string | null; + /** + * Dimension statements shown for the product, preserving labels, values, and units + */ + dimensions?: Array; + /** * URL to the product image */ @@ -255,6 +296,11 @@ export namespace AIExtractProductsResponse { */ pricing_model?: 'per_seat' | 'flat' | 'tiered' | 'freemium' | 'custom' | null; + /** + * Original or regular price before a displayed discount + */ + regular_price?: number | null; + /** * URL to the product page */ diff --git a/src/resources/news.ts b/src/resources/news.ts index ddc7513..015dbc5 100644 --- a/src/resources/news.ts +++ b/src/resources/news.ts @@ -404,6 +404,7 @@ export namespace NewsSearchParams { | 'cg' | 'ch' | 'cl' + | 'cz' | 'de' | 'fi' | 'fr' diff --git a/src/resources/web.ts b/src/resources/web.ts index 177b01b..c1c5e49 100644 --- a/src/resources/web.ts +++ b/src/resources/web.ts @@ -268,6 +268,36 @@ export namespace WebExtractResponse { numSucceeded: number; numUrls: number; + + /** + * One verified outcome per requested browser action, in request order. + */ + actionsApplied?: Array; + } + + export namespace Metadata { + export interface ActionsApplied { + instruction: string; + + /** + * Applied means the requested page state was visibly verified. Failed means it was + * not verified. Skipped means it was not attempted. + */ + status: 'applied' | 'failed' | 'skipped'; + + /** + * Visible page evidence used to verify an applied action. + */ + completionEvidence?: string; + + durationMs?: number; + + error?: string; + + method?: string; + + targetDescription?: string; + } } /** @@ -2065,9 +2095,11 @@ export namespace WebWebScrapeSitemapResponse { export interface WebExtractParams { /** - * JSON Schema for the returned data object. TypeScript Zod users can pass a JSON - * Schema generated from a Zod object; Python users can pass the equivalent JSON - * Schema object. + * JSON Schema for the returned data object. Image fields such as `image_urls` or + * `product_photos` automatically make page image references available to + * extraction, so product data and photos can be returned in one call. TypeScript + * Zod users can pass a JSON Schema generated from a Zod object; Python users can + * pass the equivalent JSON Schema object. */ schema: { [key: string]: unknown }; @@ -2077,6 +2109,13 @@ export interface WebExtractParams { */ url: string; + /** + * Optional browser actions executed in order on the requested page after it loads + * and before extraction. Requires a paid plan. When actions are provided and + * stopAfterMs is omitted, the crawl budget defaults to 110000 ms. + */ + actions?: Array; + /** * When true, every returned value must be grounded in facts stated on the page; * fields that cannot be supported by the page are returned as null/empty. When @@ -2131,7 +2170,8 @@ export interface WebExtractParams { /** * Soft time budget for the crawl in milliseconds. Min: 10000 (10s). Max: 110000 - * (110s). Default: 80000 (80s). + * (110s). Defaults to 80000 (80s), or 110000 (110s) when browser actions are + * provided. */ stopAfterMs?: number; @@ -2155,6 +2195,24 @@ export interface WebExtractParams { } export namespace WebExtractParams { + /** + * Pause for a fixed number of milliseconds before continuing to the next action. + */ + export interface WebScrapeWaitAction { + do: 'wait'; + + timeMs: number; + } + + /** + * Resolve and perform one natural-language browser action. + */ + export interface WebScrapePerformAction { + action: string; + + do: 'perform'; + } + export interface Pdf { /** * Last 1-based PDF page to parse. Must be greater than or equal to start when both @@ -3307,7 +3365,9 @@ export interface WebWebCrawlMdParams { timeoutMS?: number; /** - * Regex pattern. Only URLs matching this pattern will be followed and scraped. + * Regex pattern. Only URLs matching this pattern will be followed and scraped. An + * automatic prefix scope in the form ^ follows a redirect of the + * starting page. */ urlRegex?: string; @@ -3318,8 +3378,8 @@ export interface WebWebCrawlMdParams { useMainContentOnly?: boolean; /** - * Optional browser wait time in milliseconds after initial page load for each - * crawled page. Min: 0. Max: 30000 (30 seconds). + * Browser wait time in milliseconds after initial page load for each crawled page. + * Defaults to 3500 (3.5 seconds). Min: 0. Max: 30000 (30 seconds). */ waitForMs?: number; diff --git a/src/version.ts b/src/version.ts index e06ef68..31707fe 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '2.12.0'; // x-release-please-version +export const VERSION = '2.13.0'; // x-release-please-version diff --git a/tests/api-resources/web.test.ts b/tests/api-resources/web.test.ts index f21e506..ab05d34 100644 --- a/tests/api-resources/web.test.ts +++ b/tests/api-resources/web.test.ts @@ -38,6 +38,7 @@ describe('resource web', () => { additionalProperties: 'bar', }, url: 'https://example.com', + actions: [{ do: 'wait', timeMs: 0 }], factCheck: true, followSubdomains: true, includeFrames: true,