From 977bf14c205e4872b5ef909896560e9e704655d6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 4 Apr 2026 21:34:09 +0000 Subject: [PATCH 001/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index bee881e8..75698083 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-05a30711e18b0023520a660352d75595a050d1299bf0e3ee4a8cf55ded36aea2.yml -openapi_spec_hash: 8d0e1115a7d864f27c55cec3255d1e77 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-1a8a7dda98ab9f3c537f46c6192baed039be8f5680d3b9cc2cc227d5b06059ea.yml +openapi_spec_hash: 286076163f3b5111b915830dd21cc469 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 5a8b6f230ddf475be3a1b9d2c2e05a930a1724b8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2026 03:10:21 +0000 Subject: [PATCH 002/100] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 26 +- src/resources/brand.ts | 1167 +++++++++++++++++- tests/api-resources/brand.test.ts | 12 +- 4 files changed, 1180 insertions(+), 29 deletions(-) diff --git a/.stats.yml b/.stats.yml index 75698083..7c16337f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-1a8a7dda98ab9f3c537f46c6192baed039be8f5680d3b9cc2cc227d5b06059ea.yml -openapi_spec_hash: 286076163f3b5111b915830dd21cc469 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-095758df21a0bad753cde157cc0216339f77aec5b01de9bf36d55e34770cb611.yml +openapi_spec_hash: 4d5456700d25c12524ca030bb93d4261 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index b7981c45..09c8a1d9 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -60,9 +60,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.retrieve', params: ['domain: string;', 'force_language?: string;', 'maxSpeed?: boolean;', 'timeoutMS?: number;'], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve\n\n`client.brand.retrieve(domain: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve`\n\nRetrieve logos, backdrops, colors, industry, description, and more from any domain\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve brand data for (e.g., 'example.com', 'google.com'). Cannot be used with name or ticker parameters.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data. Works with all three lookup methods.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data. Works with all three lookup methods.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst brand = await client.brand.retrieve({ domain: 'domain' });\n\nconsole.log(brand);\n```", + "## retrieve\n\n`client.brand.retrieve(domain: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve`\n\nRetrieve logos, backdrops, colors, industry, description, and more from any domain\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve brand data for (e.g., 'example.com', 'google.com'). Cannot be used with name or ticker parameters.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data. Works with all three lookup methods.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst brand = await client.brand.retrieve({ domain: 'domain' });\n\nconsole.log(brand);\n```", perLanguage: { http: { example: @@ -107,9 +107,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_ticker\n\n`client.brand.retrieveByTicker(ticker: string, force_language?: string, maxSpeed?: boolean, ticker_exchange?: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-ticker`\n\nRetrieve brand information using a stock ticker symbol. This endpoint looks up the company associated with the ticker and returns its brand data.\n\n### Parameters\n\n- `ticker: string`\n Stock ticker symbol to retrieve brand data for (e.g., 'AAPL', 'GOOGL', 'BRK.A'). Must be 1-15 characters, letters/numbers/dots only.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `ticker_exchange?: string`\n Optional stock exchange for the ticker. Defaults to NASDAQ if not specified.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response);\n```", + "## retrieve_by_ticker\n\n`client.brand.retrieveByTicker(ticker: string, force_language?: string, maxSpeed?: boolean, ticker_exchange?: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-ticker`\n\nRetrieve brand information using a stock ticker symbol. This endpoint looks up the company associated with the ticker and returns its brand data.\n\n### Parameters\n\n- `ticker: string`\n Stock ticker symbol to retrieve brand data for (e.g., 'AAPL', 'GOOGL', 'BRK.A'). Must be 1-15 characters, letters/numbers/dots only.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `ticker_exchange?: string`\n Optional stock exchange for the ticker. Defaults to NASDAQ if not specified.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -148,9 +148,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.retrieveByIsin', params: ['isin: string;', 'force_language?: string;', 'maxSpeed?: boolean;', 'timeoutMS?: number;'], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_isin\n\n`client.brand.retrieveByIsin(isin: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-isin`\n\nRetrieve brand information using an ISIN (International Securities Identification Number). This endpoint looks up the company associated with the ISIN and returns its brand data.\n\n### Parameters\n\n- `isin: string`\n ISIN (International Securities Identification Number) to retrieve brand data for (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters followed by 9 alphanumeric characters and ending with a digit.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response);\n```", + "## retrieve_by_isin\n\n`client.brand.retrieveByIsin(isin: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-isin`\n\nRetrieve brand information using an ISIN (International Securities Identification Number). This endpoint looks up the company associated with the ISIN and returns its brand data.\n\n### Parameters\n\n- `isin: string`\n ISIN (International Securities Identification Number) to retrieve brand data for (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters followed by 9 alphanumeric characters and ending with a digit.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -195,9 +195,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_name\n\n`client.brand.retrieveByName(name: string, country_gl?: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-name`\n\nRetrieve brand information using a company name. This endpoint searches for the company by name and returns its brand data.\n\n### Parameters\n\n- `name: string`\n Company name to retrieve brand data for (e.g., 'Apple Inc', 'Microsoft Corporation'). Must be 3-30 characters.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response);\n```", + "## retrieve_by_name\n\n`client.brand.retrieveByName(name: string, country_gl?: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-name`\n\nRetrieve brand information using a company name. This endpoint searches for the company by name and returns its brand data.\n\n### Parameters\n\n- `name: string`\n Company name to retrieve brand data for (e.g., 'Apple Inc', 'Microsoft Corporation'). Must be 3-30 characters.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -236,9 +236,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.retrieveByEmail', params: ['email: string;', 'force_language?: string;', 'maxSpeed?: boolean;', 'timeoutMS?: number;'], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_email\n\n`client.brand.retrieveByEmail(email: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-email`\n\nRetrieve brand information using an email address while detecting disposable and free email addresses. This endpoint extracts the domain from the email address and returns brand data for that domain. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.\n\n### Parameters\n\n- `email: string`\n Email address to retrieve brand data for (e.g., 'contact@example.com'). The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", + "## retrieve_by_email\n\n`client.brand.retrieveByEmail(email: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-email`\n\nRetrieve brand information using an email address while detecting disposable and free email addresses. This endpoint extracts the domain from the email address and returns brand data for that domain. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.\n\n### Parameters\n\n- `email: string`\n Email address to retrieve brand data for (e.g., 'contact@example.com'). The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -287,9 +287,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## identify_from_transaction\n\n`client.brand.identifyFromTransaction(transaction_info: string, city?: string, country_gl?: string, force_language?: string, high_confidence_only?: boolean, maxSpeed?: boolean, mcc?: string, phone?: number, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/transaction_identifier`\n\nEndpoint specially designed for platforms that want to identify transaction data by the transaction title.\n\n### Parameters\n\n- `transaction_info: string`\n Transaction information to identify the brand\n\n- `city?: string`\n Optional city name to prioritize when searching for the brand.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `high_confidence_only?: boolean`\n When set to true, the API will perform an additional verification steps to ensure the identified brand matches the transaction with high confidence. Defaults to false.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `mcc?: string`\n Optional Merchant Category Code (MCC) to help identify the business category/industry. \n\n- `phone?: number`\n Optional phone number from the transaction to help verify brand match.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.identifyFromTransaction({ transaction_info: 'transaction_info' });\n\nconsole.log(response);\n```", + "## identify_from_transaction\n\n`client.brand.identifyFromTransaction(transaction_info: string, city?: string, country_gl?: string, force_language?: string, high_confidence_only?: boolean, maxSpeed?: boolean, mcc?: string, phone?: number, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/transaction_identifier`\n\nEndpoint specially designed for platforms that want to identify transaction data by the transaction title.\n\n### Parameters\n\n- `transaction_info: string`\n Transaction information to identify the brand\n\n- `city?: string`\n Optional city name to prioritize when searching for the brand.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `high_confidence_only?: boolean`\n When set to true, the API will perform an additional verification steps to ensure the identified brand matches the transaction with high confidence. Defaults to false.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `mcc?: string`\n Optional Merchant Category Code (MCC) to help identify the business category/industry. \n\n- `phone?: number`\n Optional phone number from the transaction to help verify brand match.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.identifyFromTransaction({ transaction_info: 'transaction_info' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -916,7 +916,7 @@ const EMBEDDED_READMES: { language: string; content: string }[] = [ { language: 'ruby', content: - '# Brand Dev Ruby API library\n\nThe Brand Dev Ruby library provides convenient access to the Brand Dev REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/context-dot-dev/deprecated-brand-ruby-sdk#Sorbet) for usage with Sorbet. The standard library\'s `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nDocumentation for releases of this gem can be found [on RubyDoc](https://gemdocs.org/gems/brand.dev).\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/).\n\n## Installation\n\nTo use this gem, install via Bundler by adding the following to your application\'s `Gemfile`:\n\n\n\n```ruby\ngem "brand.dev", "~> 0.0.1"\n```\n\n\n\n## Usage\n\n```ruby\nrequire "bundler/setup"\nrequire "brand_dev"\n\nbrand_dev = BrandDev::Client.new(\n api_key: ENV["BRAND_DEV_API_KEY"] # This is the default and can be omitted\n)\n\nbrand = brand_dev.brand.retrieve(domain: "REPLACE_ME")\n\nputs(brand.brand)\n```\n\n\n\n\n\n\n\n### Handling errors\n\nWhen the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `BrandDev::Errors::APIError` will be thrown:\n\n```ruby\nbegin\n brand = brand_dev.brand.retrieve(domain: "REPLACE_ME")\nrescue BrandDev::Errors::APIConnectionError => e\n puts("The server could not be reached")\n puts(e.cause) # an underlying Exception, likely raised within `net/http`\nrescue BrandDev::Errors::RateLimitError => e\n puts("A 429 status code was received; we should back off a bit.")\nrescue BrandDev::Errors::APIStatusError => e\n puts("Another non-200-range status code was received")\n puts(e.status)\nend\n```\n\nError codes are as follows:\n\n| Cause | Error Type |\n| ---------------- | -------------------------- |\n| HTTP 400 | `BadRequestError` |\n| HTTP 401 | `AuthenticationError` |\n| HTTP 403 | `PermissionDeniedError` |\n| HTTP 404 | `NotFoundError` |\n| HTTP 409 | `ConflictError` |\n| HTTP 422 | `UnprocessableEntityError` |\n| HTTP 429 | `RateLimitError` |\n| HTTP >= 500 | `InternalServerError` |\n| Other HTTP error | `APIStatusError` |\n| Timeout | `APITimeoutError` |\n| Network error | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\n\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, >=500 Internal errors, and timeouts will all be retried by default.\n\nYou can use the `max_retries` option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nbrand_dev = BrandDev::Client.new(\n max_retries: 0 # default is 2\n)\n\n# Or, configure per-request:\nbrand_dev.brand.retrieve(domain: "REPLACE_ME", request_options: {max_retries: 5})\n```\n\n### Timeouts\n\nBy default, requests will time out after 60 seconds. You can use the timeout option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nbrand_dev = BrandDev::Client.new(\n timeout: nil # default is 60\n)\n\n# Or, configure per-request:\nbrand_dev.brand.retrieve(domain: "REPLACE_ME", request_options: {timeout: 5})\n```\n\nOn timeout, `BrandDev::Errors::APITimeoutError` is raised.\n\nNote that requests that time out are retried by default.\n\n## Advanced concepts\n\n### BaseModel\n\nAll parameter and response objects inherit from `BrandDev::Internal::Type::BaseModel`, which provides several conveniences, including:\n\n1. All fields, including unknown ones, are accessible with `obj[:prop]` syntax, and can be destructured with `obj => {prop: prop}` or pattern-matching syntax.\n\n2. Structural equivalence for equality; if two API calls return the same values, comparing the responses with == will return true.\n\n3. Both instances and the classes themselves can be pretty-printed.\n\n4. Helpers such as `#to_h`, `#deep_to_h`, `#to_json`, and `#to_yaml`.\n\n### Making custom or undocumented requests\n\n#### Undocumented properties\n\nYou can send undocumented parameters to any endpoint, and read undocumented response properties, like so:\n\nNote: the `extra_` parameters of the same name overrides the documented parameters.\n\n```ruby\nbrand =\n brand_dev.brand.retrieve(\n domain: "REPLACE_ME",\n request_options: {\n extra_query: {my_query_parameter: value},\n extra_body: {my_body_parameter: value},\n extra_headers: {"my-header": value}\n }\n )\n\nputs(brand[:my_undocumented_property])\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a request, as seen in the examples above.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on, you can make requests using `client.request`, like so:\n\n```ruby\nresponse = client.request(\n method: :post,\n path: \'/undocumented/endpoint\',\n query: {"dog": "woof"},\n headers: {"useful-header": "interesting-value"},\n body: {"hello": "world"}\n)\n```\n\n### Concurrency & connection pooling\n\nThe `BrandDev::Client` instances are threadsafe, but are only are fork-safe when there are no in-flight HTTP requests.\n\nEach instance of `BrandDev::Client` has its own HTTP connection pool with a default size of 99. As such, we recommend instantiating the client once per application in most settings.\n\nWhen all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout.\n\nUnless otherwise specified, other classes in the SDK do not have locks protecting their underlying data structure.\n\n## Sorbet\n\nThis library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitions, and has no dependency on sorbet-runtime.\n\nYou can provide typesafe request parameters like so:\n\n```ruby\nbrand_dev.brand.retrieve(domain: "REPLACE_ME")\n```\n\nOr, equivalently:\n\n```ruby\n# Hashes work, but are not typesafe:\nbrand_dev.brand.retrieve(domain: "REPLACE_ME")\n\n# You can also splat a full Params class:\nparams = BrandDev::BrandRetrieveParams.new(domain: "REPLACE_ME")\nbrand_dev.brand.retrieve(**params)\n```\n\n### Enums\n\nSince this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide "tagged symbols" instead, which is always a primitive at runtime:\n\n```ruby\n# :albanian\nputs(BrandDev::BrandRetrieveParams::ForceLanguage::ALBANIAN)\n\n# Revealed type: `T.all(BrandDev::BrandRetrieveParams::ForceLanguage, Symbol)`\nT.reveal_type(BrandDev::BrandRetrieveParams::ForceLanguage::ALBANIAN)\n```\n\nEnum parameters have a "relaxed" type, so you can either pass in enum constants or their literal value:\n\n```ruby\n# Using the enum constants preserves the tagged type information:\nbrand_dev.brand.retrieve(\n force_language: BrandDev::BrandRetrieveParams::ForceLanguage::ALBANIAN,\n # …\n)\n\n# Literal values are also permissible:\nbrand_dev.brand.retrieve(\n force_language: :albanian,\n # …\n)\n```\n\n## Versioning\n\nThis package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions. As the library is in initial development and has a major version of `0`, APIs may change at any time.\n\nThis package considers improvements to the (non-runtime) `*.rbi` and `*.rbs` type definitions to be non-breaking changes.\n\n## Requirements\n\nRuby 3.2.0 or higher.\n\n## Contributing\n\nSee [the contributing documentation](https://github.com/context-dot-dev/deprecated-brand-ruby-sdk/tree/main/CONTRIBUTING.md).\n', + '# Brand Dev Ruby API library\n\nThe Brand Dev Ruby library provides convenient access to the Brand Dev REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/context-dot-dev/deprecated-brand-ruby-sdk#Sorbet) for usage with Sorbet. The standard library\'s `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nDocumentation for releases of this gem can be found [on RubyDoc](https://gemdocs.org/gems/brand.dev).\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/).\n\n## Installation\n\nTo use this gem, install via Bundler by adding the following to your application\'s `Gemfile`:\n\n\n\n```ruby\ngem "brand.dev", "~> 0.0.1"\n```\n\n\n\n## Usage\n\n```ruby\nrequire "bundler/setup"\nrequire "brand_dev"\n\nbrand_dev = BrandDev::Client.new(\n api_key: ENV["BRAND_DEV_API_KEY"] # This is the default and can be omitted\n)\n\nbrand = brand_dev.brand.retrieve(domain: "REPLACE_ME")\n\nputs(brand.brand)\n```\n\n\n\n\n\n\n\n### Handling errors\n\nWhen the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `BrandDev::Errors::APIError` will be thrown:\n\n```ruby\nbegin\n brand = brand_dev.brand.retrieve(domain: "REPLACE_ME")\nrescue BrandDev::Errors::APIConnectionError => e\n puts("The server could not be reached")\n puts(e.cause) # an underlying Exception, likely raised within `net/http`\nrescue BrandDev::Errors::RateLimitError => e\n puts("A 429 status code was received; we should back off a bit.")\nrescue BrandDev::Errors::APIStatusError => e\n puts("Another non-200-range status code was received")\n puts(e.status)\nend\n```\n\nError codes are as follows:\n\n| Cause | Error Type |\n| ---------------- | -------------------------- |\n| HTTP 400 | `BadRequestError` |\n| HTTP 401 | `AuthenticationError` |\n| HTTP 403 | `PermissionDeniedError` |\n| HTTP 404 | `NotFoundError` |\n| HTTP 409 | `ConflictError` |\n| HTTP 422 | `UnprocessableEntityError` |\n| HTTP 429 | `RateLimitError` |\n| HTTP >= 500 | `InternalServerError` |\n| Other HTTP error | `APIStatusError` |\n| Timeout | `APITimeoutError` |\n| Network error | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\n\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, >=500 Internal errors, and timeouts will all be retried by default.\n\nYou can use the `max_retries` option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nbrand_dev = BrandDev::Client.new(\n max_retries: 0 # default is 2\n)\n\n# Or, configure per-request:\nbrand_dev.brand.retrieve(domain: "REPLACE_ME", request_options: {max_retries: 5})\n```\n\n### Timeouts\n\nBy default, requests will time out after 60 seconds. You can use the timeout option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nbrand_dev = BrandDev::Client.new(\n timeout: nil # default is 60\n)\n\n# Or, configure per-request:\nbrand_dev.brand.retrieve(domain: "REPLACE_ME", request_options: {timeout: 5})\n```\n\nOn timeout, `BrandDev::Errors::APITimeoutError` is raised.\n\nNote that requests that time out are retried by default.\n\n## Advanced concepts\n\n### BaseModel\n\nAll parameter and response objects inherit from `BrandDev::Internal::Type::BaseModel`, which provides several conveniences, including:\n\n1. All fields, including unknown ones, are accessible with `obj[:prop]` syntax, and can be destructured with `obj => {prop: prop}` or pattern-matching syntax.\n\n2. Structural equivalence for equality; if two API calls return the same values, comparing the responses with == will return true.\n\n3. Both instances and the classes themselves can be pretty-printed.\n\n4. Helpers such as `#to_h`, `#deep_to_h`, `#to_json`, and `#to_yaml`.\n\n### Making custom or undocumented requests\n\n#### Undocumented properties\n\nYou can send undocumented parameters to any endpoint, and read undocumented response properties, like so:\n\nNote: the `extra_` parameters of the same name overrides the documented parameters.\n\n```ruby\nbrand =\n brand_dev.brand.retrieve(\n domain: "REPLACE_ME",\n request_options: {\n extra_query: {my_query_parameter: value},\n extra_body: {my_body_parameter: value},\n extra_headers: {"my-header": value}\n }\n )\n\nputs(brand[:my_undocumented_property])\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a request, as seen in the examples above.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on, you can make requests using `client.request`, like so:\n\n```ruby\nresponse = client.request(\n method: :post,\n path: \'/undocumented/endpoint\',\n query: {"dog": "woof"},\n headers: {"useful-header": "interesting-value"},\n body: {"hello": "world"}\n)\n```\n\n### Concurrency & connection pooling\n\nThe `BrandDev::Client` instances are threadsafe, but are only are fork-safe when there are no in-flight HTTP requests.\n\nEach instance of `BrandDev::Client` has its own HTTP connection pool with a default size of 99. As such, we recommend instantiating the client once per application in most settings.\n\nWhen all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout.\n\nUnless otherwise specified, other classes in the SDK do not have locks protecting their underlying data structure.\n\n## Sorbet\n\nThis library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitions, and has no dependency on sorbet-runtime.\n\nYou can provide typesafe request parameters like so:\n\n```ruby\nbrand_dev.brand.retrieve(domain: "REPLACE_ME")\n```\n\nOr, equivalently:\n\n```ruby\n# Hashes work, but are not typesafe:\nbrand_dev.brand.retrieve(domain: "REPLACE_ME")\n\n# You can also splat a full Params class:\nparams = BrandDev::BrandRetrieveParams.new(domain: "REPLACE_ME")\nbrand_dev.brand.retrieve(**params)\n```\n\n### Enums\n\nSince this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide "tagged symbols" instead, which is always a primitive at runtime:\n\n```ruby\n# :afrikaans\nputs(BrandDev::BrandRetrieveParams::ForceLanguage::AFRIKAANS)\n\n# Revealed type: `T.all(BrandDev::BrandRetrieveParams::ForceLanguage, Symbol)`\nT.reveal_type(BrandDev::BrandRetrieveParams::ForceLanguage::AFRIKAANS)\n```\n\nEnum parameters have a "relaxed" type, so you can either pass in enum constants or their literal value:\n\n```ruby\n# Using the enum constants preserves the tagged type information:\nbrand_dev.brand.retrieve(\n force_language: BrandDev::BrandRetrieveParams::ForceLanguage::AFRIKAANS,\n # …\n)\n\n# Literal values are also permissible:\nbrand_dev.brand.retrieve(\n force_language: :afrikaans,\n # …\n)\n```\n\n## Versioning\n\nThis package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions. As the library is in initial development and has a major version of `0`, APIs may change at any time.\n\nThis package considers improvements to the (non-runtime) `*.rbi` and `*.rbs` type definitions to be non-breaking changes.\n\n## Requirements\n\nRuby 3.2.0 or higher.\n\n## Contributing\n\nSee [the contributing documentation](https://github.com/context-dot-dev/deprecated-brand-ruby-sdk/tree/main/CONTRIBUTING.md).\n', }, { language: 'java', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 1bac96a0..19aae4d0 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -296,6 +296,133 @@ export namespace BrandRetrieveResponse { */ phone?: string; + /** + * The primary language of the brand's website content. Detected from the HTML lang + * tag, page content analysis, or social media descriptions. + */ + primary_language?: + | 'afrikaans' + | 'albanian' + | 'amharic' + | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' + | 'azeri' + | 'basque' + | 'belarusian' + | 'bengali' + | 'bosnian' + | 'bulgarian' + | 'burmese' + | 'cantonese' + | 'catalan' + | 'cebuano' + | 'chinese' + | 'corsican' + | 'croatian' + | 'czech' + | 'danish' + | 'dutch' + | 'english' + | 'esperanto' + | 'estonian' + | 'farsi' + | 'fijian' + | 'finnish' + | 'french' + | 'galician' + | 'georgian' + | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' + | 'hausa' + | 'hawaiian' + | 'hebrew' + | 'hindi' + | 'hmong' + | 'hungarian' + | 'icelandic' + | 'igbo' + | 'indonesian' + | 'irish' + | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' + | 'kazakh' + | 'khmer' + | 'kinyarwanda' + | 'korean' + | 'kurdish' + | 'kyrgyz' + | 'lao' + | 'latin' + | 'latvian' + | 'lingala' + | 'lithuanian' + | 'luxembourgish' + | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' + | 'mongolian' + | 'nepali' + | 'norwegian' + | 'odia' + | 'oromo' + | 'pashto' + | 'pidgin' + | 'polish' + | 'portuguese' + | 'punjabi' + | 'quechua' + | 'romanian' + | 'russian' + | 'samoan' + | 'scottish-gaelic' + | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' + | 'slovak' + | 'slovene' + | 'somali' + | 'spanish' + | 'sundanese' + | 'swahili' + | 'swedish' + | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' + | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' + | 'turkish' + | 'turkmen' + | 'ukrainian' + | 'urdu' + | 'uyghur' + | 'uzbek' + | 'vietnamese' + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu' + | null; + /** * The brand's slogan */ @@ -1158,6 +1285,133 @@ export namespace BrandIdentifyFromTransactionResponse { */ phone?: string; + /** + * The primary language of the brand's website content. Detected from the HTML lang + * tag, page content analysis, or social media descriptions. + */ + primary_language?: + | 'afrikaans' + | 'albanian' + | 'amharic' + | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' + | 'azeri' + | 'basque' + | 'belarusian' + | 'bengali' + | 'bosnian' + | 'bulgarian' + | 'burmese' + | 'cantonese' + | 'catalan' + | 'cebuano' + | 'chinese' + | 'corsican' + | 'croatian' + | 'czech' + | 'danish' + | 'dutch' + | 'english' + | 'esperanto' + | 'estonian' + | 'farsi' + | 'fijian' + | 'finnish' + | 'french' + | 'galician' + | 'georgian' + | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' + | 'hausa' + | 'hawaiian' + | 'hebrew' + | 'hindi' + | 'hmong' + | 'hungarian' + | 'icelandic' + | 'igbo' + | 'indonesian' + | 'irish' + | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' + | 'kazakh' + | 'khmer' + | 'kinyarwanda' + | 'korean' + | 'kurdish' + | 'kyrgyz' + | 'lao' + | 'latin' + | 'latvian' + | 'lingala' + | 'lithuanian' + | 'luxembourgish' + | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' + | 'mongolian' + | 'nepali' + | 'norwegian' + | 'odia' + | 'oromo' + | 'pashto' + | 'pidgin' + | 'polish' + | 'portuguese' + | 'punjabi' + | 'quechua' + | 'romanian' + | 'russian' + | 'samoan' + | 'scottish-gaelic' + | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' + | 'slovak' + | 'slovene' + | 'somali' + | 'spanish' + | 'sundanese' + | 'swahili' + | 'swedish' + | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' + | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' + | 'turkish' + | 'turkmen' + | 'ukrainian' + | 'urdu' + | 'uyghur' + | 'uzbek' + | 'vietnamese' + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu' + | null; + /** * The brand's slogan */ @@ -1791,6 +2045,133 @@ export namespace BrandRetrieveByEmailResponse { */ phone?: string; + /** + * The primary language of the brand's website content. Detected from the HTML lang + * tag, page content analysis, or social media descriptions. + */ + primary_language?: + | 'afrikaans' + | 'albanian' + | 'amharic' + | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' + | 'azeri' + | 'basque' + | 'belarusian' + | 'bengali' + | 'bosnian' + | 'bulgarian' + | 'burmese' + | 'cantonese' + | 'catalan' + | 'cebuano' + | 'chinese' + | 'corsican' + | 'croatian' + | 'czech' + | 'danish' + | 'dutch' + | 'english' + | 'esperanto' + | 'estonian' + | 'farsi' + | 'fijian' + | 'finnish' + | 'french' + | 'galician' + | 'georgian' + | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' + | 'hausa' + | 'hawaiian' + | 'hebrew' + | 'hindi' + | 'hmong' + | 'hungarian' + | 'icelandic' + | 'igbo' + | 'indonesian' + | 'irish' + | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' + | 'kazakh' + | 'khmer' + | 'kinyarwanda' + | 'korean' + | 'kurdish' + | 'kyrgyz' + | 'lao' + | 'latin' + | 'latvian' + | 'lingala' + | 'lithuanian' + | 'luxembourgish' + | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' + | 'mongolian' + | 'nepali' + | 'norwegian' + | 'odia' + | 'oromo' + | 'pashto' + | 'pidgin' + | 'polish' + | 'portuguese' + | 'punjabi' + | 'quechua' + | 'romanian' + | 'russian' + | 'samoan' + | 'scottish-gaelic' + | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' + | 'slovak' + | 'slovene' + | 'somali' + | 'spanish' + | 'sundanese' + | 'swahili' + | 'swedish' + | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' + | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' + | 'turkish' + | 'turkmen' + | 'ukrainian' + | 'urdu' + | 'uyghur' + | 'uzbek' + | 'vietnamese' + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu' + | null; + /** * The brand's slogan */ @@ -2390,6 +2771,133 @@ export namespace BrandRetrieveByIsinResponse { */ phone?: string; + /** + * The primary language of the brand's website content. Detected from the HTML lang + * tag, page content analysis, or social media descriptions. + */ + primary_language?: + | 'afrikaans' + | 'albanian' + | 'amharic' + | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' + | 'azeri' + | 'basque' + | 'belarusian' + | 'bengali' + | 'bosnian' + | 'bulgarian' + | 'burmese' + | 'cantonese' + | 'catalan' + | 'cebuano' + | 'chinese' + | 'corsican' + | 'croatian' + | 'czech' + | 'danish' + | 'dutch' + | 'english' + | 'esperanto' + | 'estonian' + | 'farsi' + | 'fijian' + | 'finnish' + | 'french' + | 'galician' + | 'georgian' + | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' + | 'hausa' + | 'hawaiian' + | 'hebrew' + | 'hindi' + | 'hmong' + | 'hungarian' + | 'icelandic' + | 'igbo' + | 'indonesian' + | 'irish' + | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' + | 'kazakh' + | 'khmer' + | 'kinyarwanda' + | 'korean' + | 'kurdish' + | 'kyrgyz' + | 'lao' + | 'latin' + | 'latvian' + | 'lingala' + | 'lithuanian' + | 'luxembourgish' + | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' + | 'mongolian' + | 'nepali' + | 'norwegian' + | 'odia' + | 'oromo' + | 'pashto' + | 'pidgin' + | 'polish' + | 'portuguese' + | 'punjabi' + | 'quechua' + | 'romanian' + | 'russian' + | 'samoan' + | 'scottish-gaelic' + | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' + | 'slovak' + | 'slovene' + | 'somali' + | 'spanish' + | 'sundanese' + | 'swahili' + | 'swedish' + | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' + | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' + | 'turkish' + | 'turkmen' + | 'ukrainian' + | 'urdu' + | 'uyghur' + | 'uzbek' + | 'vietnamese' + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu' + | null; + /** * The brand's slogan */ @@ -2989,6 +3497,133 @@ export namespace BrandRetrieveByNameResponse { */ phone?: string; + /** + * The primary language of the brand's website content. Detected from the HTML lang + * tag, page content analysis, or social media descriptions. + */ + primary_language?: + | 'afrikaans' + | 'albanian' + | 'amharic' + | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' + | 'azeri' + | 'basque' + | 'belarusian' + | 'bengali' + | 'bosnian' + | 'bulgarian' + | 'burmese' + | 'cantonese' + | 'catalan' + | 'cebuano' + | 'chinese' + | 'corsican' + | 'croatian' + | 'czech' + | 'danish' + | 'dutch' + | 'english' + | 'esperanto' + | 'estonian' + | 'farsi' + | 'fijian' + | 'finnish' + | 'french' + | 'galician' + | 'georgian' + | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' + | 'hausa' + | 'hawaiian' + | 'hebrew' + | 'hindi' + | 'hmong' + | 'hungarian' + | 'icelandic' + | 'igbo' + | 'indonesian' + | 'irish' + | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' + | 'kazakh' + | 'khmer' + | 'kinyarwanda' + | 'korean' + | 'kurdish' + | 'kyrgyz' + | 'lao' + | 'latin' + | 'latvian' + | 'lingala' + | 'lithuanian' + | 'luxembourgish' + | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' + | 'mongolian' + | 'nepali' + | 'norwegian' + | 'odia' + | 'oromo' + | 'pashto' + | 'pidgin' + | 'polish' + | 'portuguese' + | 'punjabi' + | 'quechua' + | 'romanian' + | 'russian' + | 'samoan' + | 'scottish-gaelic' + | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' + | 'slovak' + | 'slovene' + | 'somali' + | 'spanish' + | 'sundanese' + | 'swahili' + | 'swedish' + | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' + | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' + | 'turkish' + | 'turkmen' + | 'ukrainian' + | 'urdu' + | 'uyghur' + | 'uzbek' + | 'vietnamese' + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu' + | null; + /** * The brand's slogan */ @@ -3588,6 +4223,133 @@ export namespace BrandRetrieveByTickerResponse { */ phone?: string; + /** + * The primary language of the brand's website content. Detected from the HTML lang + * tag, page content analysis, or social media descriptions. + */ + primary_language?: + | 'afrikaans' + | 'albanian' + | 'amharic' + | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' + | 'azeri' + | 'basque' + | 'belarusian' + | 'bengali' + | 'bosnian' + | 'bulgarian' + | 'burmese' + | 'cantonese' + | 'catalan' + | 'cebuano' + | 'chinese' + | 'corsican' + | 'croatian' + | 'czech' + | 'danish' + | 'dutch' + | 'english' + | 'esperanto' + | 'estonian' + | 'farsi' + | 'fijian' + | 'finnish' + | 'french' + | 'galician' + | 'georgian' + | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' + | 'hausa' + | 'hawaiian' + | 'hebrew' + | 'hindi' + | 'hmong' + | 'hungarian' + | 'icelandic' + | 'igbo' + | 'indonesian' + | 'irish' + | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' + | 'kazakh' + | 'khmer' + | 'kinyarwanda' + | 'korean' + | 'kurdish' + | 'kyrgyz' + | 'lao' + | 'latin' + | 'latvian' + | 'lingala' + | 'lithuanian' + | 'luxembourgish' + | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' + | 'mongolian' + | 'nepali' + | 'norwegian' + | 'odia' + | 'oromo' + | 'pashto' + | 'pidgin' + | 'polish' + | 'portuguese' + | 'punjabi' + | 'quechua' + | 'romanian' + | 'russian' + | 'samoan' + | 'scottish-gaelic' + | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' + | 'slovak' + | 'slovene' + | 'somali' + | 'spanish' + | 'sundanese' + | 'swahili' + | 'swedish' + | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' + | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' + | 'turkish' + | 'turkmen' + | 'ukrainian' + | 'urdu' + | 'uyghur' + | 'uzbek' + | 'vietnamese' + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu' + | null; + /** * The brand's slogan */ @@ -4970,65 +5732,129 @@ export interface BrandRetrieveParams { domain: string; /** - * Optional parameter to force the language of the retrieved brand data. Works with - * all three lookup methods. + * Optional parameter to force the language of the retrieved brand data. */ force_language?: + | 'afrikaans' | 'albanian' + | 'amharic' | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' | 'azeri' + | 'basque' + | 'belarusian' | 'bengali' + | 'bosnian' | 'bulgarian' + | 'burmese' | 'cantonese' + | 'catalan' | 'cebuano' + | 'chinese' + | 'corsican' | 'croatian' | 'czech' | 'danish' | 'dutch' | 'english' + | 'esperanto' | 'estonian' | 'farsi' + | 'fijian' | 'finnish' | 'french' + | 'galician' + | 'georgian' | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' | 'hausa' | 'hawaiian' + | 'hebrew' | 'hindi' + | 'hmong' | 'hungarian' | 'icelandic' + | 'igbo' | 'indonesian' + | 'irish' | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' | 'kazakh' + | 'khmer' + | 'kinyarwanda' | 'korean' + | 'kurdish' | 'kyrgyz' + | 'lao' | 'latin' | 'latvian' + | 'lingala' | 'lithuanian' + | 'luxembourgish' | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' | 'mongolian' | 'nepali' | 'norwegian' + | 'odia' + | 'oromo' | 'pashto' | 'pidgin' | 'polish' | 'portuguese' + | 'punjabi' + | 'quechua' | 'romanian' | 'russian' + | 'samoan' + | 'scottish-gaelic' | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' | 'slovak' | 'slovene' | 'somali' | 'spanish' + | 'sundanese' | 'swahili' | 'swedish' | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' | 'turkish' + | 'turkmen' | 'ukrainian' | 'urdu' + | 'uyghur' | 'uzbek' | 'vietnamese' - | 'welsh'; + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu'; /** * Optional parameter to optimize the API call for maximum speed. When set to true, @@ -5484,61 +6310,126 @@ export interface BrandIdentifyFromTransactionParams { * Optional parameter to force the language of the retrieved brand data. */ force_language?: + | 'afrikaans' | 'albanian' + | 'amharic' | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' | 'azeri' + | 'basque' + | 'belarusian' | 'bengali' + | 'bosnian' | 'bulgarian' + | 'burmese' | 'cantonese' + | 'catalan' | 'cebuano' + | 'chinese' + | 'corsican' | 'croatian' | 'czech' | 'danish' | 'dutch' | 'english' + | 'esperanto' | 'estonian' | 'farsi' + | 'fijian' | 'finnish' | 'french' + | 'galician' + | 'georgian' | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' | 'hausa' | 'hawaiian' + | 'hebrew' | 'hindi' + | 'hmong' | 'hungarian' | 'icelandic' + | 'igbo' | 'indonesian' + | 'irish' | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' | 'kazakh' + | 'khmer' + | 'kinyarwanda' | 'korean' + | 'kurdish' | 'kyrgyz' + | 'lao' | 'latin' | 'latvian' + | 'lingala' | 'lithuanian' + | 'luxembourgish' | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' | 'mongolian' | 'nepali' | 'norwegian' + | 'odia' + | 'oromo' | 'pashto' | 'pidgin' | 'polish' | 'portuguese' + | 'punjabi' + | 'quechua' | 'romanian' | 'russian' + | 'samoan' + | 'scottish-gaelic' | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' | 'slovak' | 'slovene' | 'somali' | 'spanish' + | 'sundanese' | 'swahili' | 'swedish' | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' | 'turkish' + | 'turkmen' | 'ukrainian' | 'urdu' + | 'uyghur' | 'uzbek' | 'vietnamese' - | 'welsh'; + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu'; /** * When set to true, the API will perform an additional verification steps to @@ -5615,61 +6506,126 @@ export interface BrandRetrieveByEmailParams { * Optional parameter to force the language of the retrieved brand data. */ force_language?: + | 'afrikaans' | 'albanian' + | 'amharic' | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' | 'azeri' + | 'basque' + | 'belarusian' | 'bengali' + | 'bosnian' | 'bulgarian' + | 'burmese' | 'cantonese' + | 'catalan' | 'cebuano' + | 'chinese' + | 'corsican' | 'croatian' | 'czech' | 'danish' | 'dutch' | 'english' + | 'esperanto' | 'estonian' | 'farsi' + | 'fijian' | 'finnish' | 'french' + | 'galician' + | 'georgian' | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' | 'hausa' | 'hawaiian' + | 'hebrew' | 'hindi' + | 'hmong' | 'hungarian' | 'icelandic' + | 'igbo' | 'indonesian' + | 'irish' | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' | 'kazakh' + | 'khmer' + | 'kinyarwanda' | 'korean' + | 'kurdish' | 'kyrgyz' + | 'lao' | 'latin' | 'latvian' + | 'lingala' | 'lithuanian' + | 'luxembourgish' | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' | 'mongolian' | 'nepali' | 'norwegian' + | 'odia' + | 'oromo' | 'pashto' | 'pidgin' | 'polish' | 'portuguese' + | 'punjabi' + | 'quechua' | 'romanian' | 'russian' + | 'samoan' + | 'scottish-gaelic' | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' | 'slovak' | 'slovene' | 'somali' | 'spanish' + | 'sundanese' | 'swahili' | 'swedish' | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' | 'turkish' + | 'turkmen' | 'ukrainian' | 'urdu' + | 'uyghur' | 'uzbek' | 'vietnamese' - | 'welsh'; + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu'; /** * Optional parameter to optimize the API call for maximum speed. When set to true, @@ -5698,61 +6654,126 @@ export interface BrandRetrieveByIsinParams { * Optional parameter to force the language of the retrieved brand data. */ force_language?: + | 'afrikaans' | 'albanian' + | 'amharic' | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' | 'azeri' + | 'basque' + | 'belarusian' | 'bengali' + | 'bosnian' | 'bulgarian' + | 'burmese' | 'cantonese' + | 'catalan' | 'cebuano' + | 'chinese' + | 'corsican' | 'croatian' | 'czech' | 'danish' | 'dutch' | 'english' + | 'esperanto' | 'estonian' | 'farsi' + | 'fijian' | 'finnish' | 'french' + | 'galician' + | 'georgian' | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' | 'hausa' | 'hawaiian' + | 'hebrew' | 'hindi' + | 'hmong' | 'hungarian' | 'icelandic' + | 'igbo' | 'indonesian' + | 'irish' | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' | 'kazakh' + | 'khmer' + | 'kinyarwanda' | 'korean' + | 'kurdish' | 'kyrgyz' + | 'lao' | 'latin' | 'latvian' + | 'lingala' | 'lithuanian' + | 'luxembourgish' | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' | 'mongolian' | 'nepali' | 'norwegian' + | 'odia' + | 'oromo' | 'pashto' | 'pidgin' | 'polish' | 'portuguese' + | 'punjabi' + | 'quechua' | 'romanian' | 'russian' + | 'samoan' + | 'scottish-gaelic' | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' | 'slovak' | 'slovene' | 'somali' | 'spanish' + | 'sundanese' | 'swahili' | 'swedish' | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' | 'turkish' + | 'turkmen' | 'ukrainian' | 'urdu' + | 'uyghur' | 'uzbek' | 'vietnamese' - | 'welsh'; + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu'; /** * Optional parameter to optimize the API call for maximum speed. When set to true, @@ -6025,61 +7046,126 @@ export interface BrandRetrieveByNameParams { * Optional parameter to force the language of the retrieved brand data. */ force_language?: + | 'afrikaans' | 'albanian' + | 'amharic' | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' | 'azeri' + | 'basque' + | 'belarusian' | 'bengali' + | 'bosnian' | 'bulgarian' + | 'burmese' | 'cantonese' + | 'catalan' | 'cebuano' + | 'chinese' + | 'corsican' | 'croatian' | 'czech' | 'danish' | 'dutch' | 'english' + | 'esperanto' | 'estonian' | 'farsi' + | 'fijian' | 'finnish' | 'french' + | 'galician' + | 'georgian' | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' | 'hausa' | 'hawaiian' + | 'hebrew' | 'hindi' + | 'hmong' | 'hungarian' | 'icelandic' + | 'igbo' | 'indonesian' + | 'irish' | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' | 'kazakh' + | 'khmer' + | 'kinyarwanda' | 'korean' + | 'kurdish' | 'kyrgyz' + | 'lao' | 'latin' | 'latvian' + | 'lingala' | 'lithuanian' + | 'luxembourgish' | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' | 'mongolian' | 'nepali' | 'norwegian' + | 'odia' + | 'oromo' | 'pashto' | 'pidgin' | 'polish' | 'portuguese' + | 'punjabi' + | 'quechua' | 'romanian' | 'russian' + | 'samoan' + | 'scottish-gaelic' | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' | 'slovak' | 'slovene' | 'somali' | 'spanish' + | 'sundanese' | 'swahili' | 'swedish' | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' | 'turkish' + | 'turkmen' | 'ukrainian' | 'urdu' + | 'uyghur' | 'uzbek' | 'vietnamese' - | 'welsh'; + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu'; /** * Optional parameter to optimize the API call for maximum speed. When set to true, @@ -6107,61 +7193,126 @@ export interface BrandRetrieveByTickerParams { * Optional parameter to force the language of the retrieved brand data. */ force_language?: + | 'afrikaans' | 'albanian' + | 'amharic' | 'arabic' + | 'armenian' + | 'assamese' + | 'aymara' | 'azeri' + | 'basque' + | 'belarusian' | 'bengali' + | 'bosnian' | 'bulgarian' + | 'burmese' | 'cantonese' + | 'catalan' | 'cebuano' + | 'chinese' + | 'corsican' | 'croatian' | 'czech' | 'danish' | 'dutch' | 'english' + | 'esperanto' | 'estonian' | 'farsi' + | 'fijian' | 'finnish' | 'french' + | 'galician' + | 'georgian' | 'german' + | 'greek' + | 'guarani' + | 'gujarati' + | 'haitian-creole' | 'hausa' | 'hawaiian' + | 'hebrew' | 'hindi' + | 'hmong' | 'hungarian' | 'icelandic' + | 'igbo' | 'indonesian' + | 'irish' | 'italian' + | 'japanese' + | 'javanese' + | 'kannada' | 'kazakh' + | 'khmer' + | 'kinyarwanda' | 'korean' + | 'kurdish' | 'kyrgyz' + | 'lao' | 'latin' | 'latvian' + | 'lingala' | 'lithuanian' + | 'luxembourgish' | 'macedonian' + | 'malagasy' + | 'malay' + | 'malayalam' + | 'maltese' + | 'maori' + | 'marathi' | 'mongolian' | 'nepali' | 'norwegian' + | 'odia' + | 'oromo' | 'pashto' | 'pidgin' | 'polish' | 'portuguese' + | 'punjabi' + | 'quechua' | 'romanian' | 'russian' + | 'samoan' + | 'scottish-gaelic' | 'serbian' + | 'sesotho' + | 'shona' + | 'sindhi' + | 'sinhala' | 'slovak' | 'slovene' | 'somali' | 'spanish' + | 'sundanese' | 'swahili' | 'swedish' | 'tagalog' + | 'tajik' + | 'tamil' + | 'tatar' + | 'telugu' | 'thai' + | 'tibetan' + | 'tigrinya' + | 'tongan' + | 'tswana' | 'turkish' + | 'turkmen' | 'ukrainian' | 'urdu' + | 'uyghur' | 'uzbek' | 'vietnamese' - | 'welsh'; + | 'welsh' + | 'wolof' + | 'xhosa' + | 'yiddish' + | 'yoruba' + | 'zulu'; /** * Optional parameter to optimize the API call for maximum speed. When set to true, diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index efd4b57f..117f656e 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -24,7 +24,7 @@ describe('resource brand', () => { test.skip('retrieve: required and optional params', async () => { const response = await client.brand.retrieve({ domain: 'domain', - force_language: 'albanian', + force_language: 'afrikaans', maxSpeed: true, timeoutMS: 1000, }); @@ -154,7 +154,7 @@ describe('resource brand', () => { transaction_info: 'transaction_info', city: 'city', country_gl: 'ad', - force_language: 'albanian', + force_language: 'afrikaans', high_confidence_only: true, maxSpeed: true, mcc: 'mcc', @@ -213,7 +213,7 @@ describe('resource brand', () => { test.skip('retrieveByEmail: required and optional params', async () => { const response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com', - force_language: 'albanian', + force_language: 'afrikaans', maxSpeed: true, timeoutMS: 1000, }); @@ -235,7 +235,7 @@ describe('resource brand', () => { test.skip('retrieveByIsin: required and optional params', async () => { const response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993', - force_language: 'albanian', + force_language: 'afrikaans', maxSpeed: true, timeoutMS: 1000, }); @@ -258,7 +258,7 @@ describe('resource brand', () => { const response = await client.brand.retrieveByName({ name: 'xxx', country_gl: 'ad', - force_language: 'albanian', + force_language: 'afrikaans', maxSpeed: true, timeoutMS: 1000, }); @@ -280,7 +280,7 @@ describe('resource brand', () => { test.skip('retrieveByTicker: required and optional params', async () => { const response = await client.brand.retrieveByTicker({ ticker: 'ticker', - force_language: 'albanian', + force_language: 'afrikaans', maxSpeed: true, ticker_exchange: 'AMEX', timeoutMS: 1000, From 2951a65b2f64fff438a445501b8faa095023d48b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 5 Apr 2026 15:20:52 +0000 Subject: [PATCH 003/100] feat(api): api update --- .stats.yml | 4 +- src/resources/brand.ts | 222 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 206 insertions(+), 20 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7c16337f..eb616189 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-095758df21a0bad753cde157cc0216339f77aec5b01de9bf36d55e34770cb611.yml -openapi_spec_hash: 4d5456700d25c12524ca030bb93d4261 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-f2509d0b758e88572e5a8145b8296cb330154727d9797e615ad19e44e050af26.yml +openapi_spec_hash: 40640a033ee09bda79ec066ba3744206 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 19aae4d0..8c35602b 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -917,9 +917,40 @@ export namespace BrandRetrieveResponse { export interface Social { /** - * Type of social media, e.g., 'facebook', 'twitter' - */ - type?: string; + * Type of social media platform + */ + type?: + | 'x' + | 'facebook' + | 'instagram' + | 'linkedin' + | 'youtube' + | 'pinterest' + | 'tiktok' + | 'dribbble' + | 'github' + | 'behance' + | 'snapchat' + | 'whatsapp' + | 'telegram' + | 'line' + | 'discord' + | 'twitch' + | 'vimeo' + | 'imdb' + | 'tumblr' + | 'flickr' + | 'giphy' + | 'medium' + | 'spotify' + | 'soundcloud' + | 'tripadvisor' + | 'yelp' + | 'producthunt' + | 'reddit' + | 'crunchbase' + | 'appstore' + | 'playstore'; /** * URL of the social media page @@ -1906,9 +1937,40 @@ export namespace BrandIdentifyFromTransactionResponse { export interface Social { /** - * Type of social media, e.g., 'facebook', 'twitter' - */ - type?: string; + * Type of social media platform + */ + type?: + | 'x' + | 'facebook' + | 'instagram' + | 'linkedin' + | 'youtube' + | 'pinterest' + | 'tiktok' + | 'dribbble' + | 'github' + | 'behance' + | 'snapchat' + | 'whatsapp' + | 'telegram' + | 'line' + | 'discord' + | 'twitch' + | 'vimeo' + | 'imdb' + | 'tumblr' + | 'flickr' + | 'giphy' + | 'medium' + | 'spotify' + | 'soundcloud' + | 'tripadvisor' + | 'yelp' + | 'producthunt' + | 'reddit' + | 'crunchbase' + | 'appstore' + | 'playstore'; /** * URL of the social media page @@ -2666,9 +2728,40 @@ export namespace BrandRetrieveByEmailResponse { export interface Social { /** - * Type of social media, e.g., 'facebook', 'twitter' - */ - type?: string; + * Type of social media platform + */ + type?: + | 'x' + | 'facebook' + | 'instagram' + | 'linkedin' + | 'youtube' + | 'pinterest' + | 'tiktok' + | 'dribbble' + | 'github' + | 'behance' + | 'snapchat' + | 'whatsapp' + | 'telegram' + | 'line' + | 'discord' + | 'twitch' + | 'vimeo' + | 'imdb' + | 'tumblr' + | 'flickr' + | 'giphy' + | 'medium' + | 'spotify' + | 'soundcloud' + | 'tripadvisor' + | 'yelp' + | 'producthunt' + | 'reddit' + | 'crunchbase' + | 'appstore' + | 'playstore'; /** * URL of the social media page @@ -3392,9 +3485,40 @@ export namespace BrandRetrieveByIsinResponse { export interface Social { /** - * Type of social media, e.g., 'facebook', 'twitter' - */ - type?: string; + * Type of social media platform + */ + type?: + | 'x' + | 'facebook' + | 'instagram' + | 'linkedin' + | 'youtube' + | 'pinterest' + | 'tiktok' + | 'dribbble' + | 'github' + | 'behance' + | 'snapchat' + | 'whatsapp' + | 'telegram' + | 'line' + | 'discord' + | 'twitch' + | 'vimeo' + | 'imdb' + | 'tumblr' + | 'flickr' + | 'giphy' + | 'medium' + | 'spotify' + | 'soundcloud' + | 'tripadvisor' + | 'yelp' + | 'producthunt' + | 'reddit' + | 'crunchbase' + | 'appstore' + | 'playstore'; /** * URL of the social media page @@ -4118,9 +4242,40 @@ export namespace BrandRetrieveByNameResponse { export interface Social { /** - * Type of social media, e.g., 'facebook', 'twitter' - */ - type?: string; + * Type of social media platform + */ + type?: + | 'x' + | 'facebook' + | 'instagram' + | 'linkedin' + | 'youtube' + | 'pinterest' + | 'tiktok' + | 'dribbble' + | 'github' + | 'behance' + | 'snapchat' + | 'whatsapp' + | 'telegram' + | 'line' + | 'discord' + | 'twitch' + | 'vimeo' + | 'imdb' + | 'tumblr' + | 'flickr' + | 'giphy' + | 'medium' + | 'spotify' + | 'soundcloud' + | 'tripadvisor' + | 'yelp' + | 'producthunt' + | 'reddit' + | 'crunchbase' + | 'appstore' + | 'playstore'; /** * URL of the social media page @@ -4844,9 +4999,40 @@ export namespace BrandRetrieveByTickerResponse { export interface Social { /** - * Type of social media, e.g., 'facebook', 'twitter' - */ - type?: string; + * Type of social media platform + */ + type?: + | 'x' + | 'facebook' + | 'instagram' + | 'linkedin' + | 'youtube' + | 'pinterest' + | 'tiktok' + | 'dribbble' + | 'github' + | 'behance' + | 'snapchat' + | 'whatsapp' + | 'telegram' + | 'line' + | 'discord' + | 'twitch' + | 'vimeo' + | 'imdb' + | 'tumblr' + | 'flickr' + | 'giphy' + | 'medium' + | 'spotify' + | 'soundcloud' + | 'tripadvisor' + | 'yelp' + | 'producthunt' + | 'reddit' + | 'crunchbase' + | 'appstore' + | 'playstore'; /** * URL of the social media page From 18990e28444884c123f8cff50c7763ff5f3562cf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 7 Apr 2026 06:34:29 +0000 Subject: [PATCH 004/100] chore(internal): fix MCP server import ordering --- packages/mcp-server/src/instructions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/src/instructions.ts b/packages/mcp-server/src/instructions.ts index d580392b..02e18eb3 100644 --- a/packages/mcp-server/src/instructions.ts +++ b/packages/mcp-server/src/instructions.ts @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import fs from 'fs/promises'; -import { readEnv } from './util'; import { getLogger } from './logger'; +import { readEnv } from './util'; const INSTRUCTIONS_CACHE_TTL_MS = 15 * 60 * 1000; // 15 minutes From 39503b60104352275076fefa2b821ee1a7f9a2d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 08:29:26 +0000 Subject: [PATCH 005/100] chore(mcp-server): increase local docs search result count from 5 to 10 --- packages/mcp-server/src/docs-search-tool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/src/docs-search-tool.ts b/packages/mcp-server/src/docs-search-tool.ts index 38784c0f..316a9816 100644 --- a/packages/mcp-server/src/docs-search-tool.ts +++ b/packages/mcp-server/src/docs-search-tool.ts @@ -63,7 +63,7 @@ async function searchLocal(args: Record): Promise { query, language, detail, - maxResults: 5, + maxResults: 10, }).results; } From 54a4dc6a834ee5801f0bcc326a0446598121d844 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 08:31:24 +0000 Subject: [PATCH 006/100] chore(internal): codegen related update --- packages/mcp-server/src/util.ts | 4 ++-- src/internal/utils/env.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/mcp-server/src/util.ts b/packages/mcp-server/src/util.ts index 40ed5501..069a2b47 100644 --- a/packages/mcp-server/src/util.ts +++ b/packages/mcp-server/src/util.ts @@ -2,9 +2,9 @@ export const readEnv = (env: string): string | undefined => { if (typeof (globalThis as any).process !== 'undefined') { - return (globalThis as any).process.env?.[env]?.trim(); + return (globalThis as any).process.env?.[env]?.trim() || undefined; } else if (typeof (globalThis as any).Deno !== 'undefined') { - return (globalThis as any).Deno.env?.get?.(env)?.trim(); + return (globalThis as any).Deno.env?.get?.(env)?.trim() || undefined; } return; }; diff --git a/src/internal/utils/env.ts b/src/internal/utils/env.ts index 2d848007..cc5fa0fa 100644 --- a/src/internal/utils/env.ts +++ b/src/internal/utils/env.ts @@ -9,10 +9,10 @@ */ export const readEnv = (env: string): string | undefined => { if (typeof (globalThis as any).process !== 'undefined') { - return (globalThis as any).process.env?.[env]?.trim() ?? undefined; + return (globalThis as any).process.env?.[env]?.trim() || undefined; } if (typeof (globalThis as any).Deno !== 'undefined') { - return (globalThis as any).Deno.env?.get?.(env)?.trim(); + return (globalThis as any).Deno.env?.get?.(env)?.trim() || undefined; } return undefined; }; From 9c5127f56d1a7cecd870ed28f39299ad07435f84 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 9 Apr 2026 15:46:33 +0000 Subject: [PATCH 007/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 15 ++++++------ src/resources/brand.ts | 22 +++++++++++++---- tests/api-resources/brand.test.ts | 25 +++++++++++++------- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/.stats.yml b/.stats.yml index eb616189..97c1cfd7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-f2509d0b758e88572e5a8145b8296cb330154727d9797e615ad19e44e050af26.yml -openapi_spec_hash: 40640a033ee09bda79ec066ba3744206 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-905e35387d755a84a2e7cd711f31eeea130e08a83bb7b39d3fa5445a187ef62f.yml +openapi_spec_hash: 205b2c17cb40ad54d76c2c06c9e5dda4 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 09c8a1d9..a9512562 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -571,11 +571,12 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'get', summary: 'Take screenshot of website', description: - 'Capture a screenshot of a website. Supports both viewport (standard browser view) and full-page screenshots. Can also screenshot specific page types (login, pricing, etc.) by using heuristics to find the appropriate URL. Returns a URL to the uploaded screenshot image hosted on our CDN.', + "Capture a screenshot of a website. Supports both viewport (standard browser view) and full-page screenshots. Can also screenshot specific page types (login, pricing, etc.) by using heuristics to find the appropriate URL. Either 'domain' or 'directUrl' must be provided as a query parameter, but not both. Returns a URL to the uploaded screenshot image hosted on our CDN.", stainlessPath: '(resource) brand > (method) screenshot', qualified: 'client.brand.screenshot', params: [ - 'domain: string;', + 'directUrl?: string;', + 'domain?: string;', "fullScreenshot?: 'true' | 'false';", "page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact';", "prioritize?: 'speed' | 'quality';", @@ -583,7 +584,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ code?: number; domain?: string; screenshot?: string; screenshotType?: 'viewport' | 'fullPage'; status?: string; }", markdown: - "## screenshot\n\n`client.brand.screenshot(domain: string, fullScreenshot?: 'true' | 'false', page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact', prioritize?: 'speed' | 'quality'): { code?: number; domain?: string; screenshot?: string; screenshotType?: 'viewport' | 'fullPage'; status?: string; }`\n\n**get** `/brand/screenshot`\n\nCapture a screenshot of a website. Supports both viewport (standard browser view) and full-page screenshots. Can also screenshot specific page types (login, pricing, etc.) by using heuristics to find the appropriate URL. Returns a URL to the uploaded screenshot image hosted on our CDN.\n\n### Parameters\n\n- `domain: string`\n Domain name to take screenshot of (e.g., 'example.com', 'google.com'). The domain will be automatically normalized and validated.\n\n- `fullScreenshot?: 'true' | 'false'`\n Optional parameter to determine screenshot type. If 'true', takes a full page screenshot capturing all content. If 'false' or not provided, takes a viewport screenshot (standard browser view).\n\n- `page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact'`\n Optional parameter to specify which page type to screenshot. If provided, the system will scrape the domain's links and use heuristics to find the most appropriate URL for the specified page type (30 supported languages). If not provided, screenshots the main domain landing page.\n\n- `prioritize?: 'speed' | 'quality'`\n Optional parameter to prioritize screenshot capture. If 'speed', optimizes for faster capture with basic quality. If 'quality', optimizes for higher quality with longer wait times. Defaults to 'quality' if not provided.\n\n### Returns\n\n- `{ code?: number; domain?: string; screenshot?: string; screenshotType?: 'viewport' | 'fullPage'; status?: string; }`\n\n - `code?: number`\n - `domain?: string`\n - `screenshot?: string`\n - `screenshotType?: 'viewport' | 'fullPage'`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.screenshot({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## screenshot\n\n`client.brand.screenshot(directUrl?: string, domain?: string, fullScreenshot?: 'true' | 'false', page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact', prioritize?: 'speed' | 'quality'): { code?: number; domain?: string; screenshot?: string; screenshotType?: 'viewport' | 'fullPage'; status?: string; }`\n\n**get** `/brand/screenshot`\n\nCapture a screenshot of a website. Supports both viewport (standard browser view) and full-page screenshots. Can also screenshot specific page types (login, pricing, etc.) by using heuristics to find the appropriate URL. Either 'domain' or 'directUrl' must be provided as a query parameter, but not both. Returns a URL to the uploaded screenshot image hosted on our CDN.\n\n### Parameters\n\n- `directUrl?: string`\n A specific URL to screenshot directly, bypassing domain resolution (e.g., 'https://example.com/pricing'). When provided, the screenshot is taken of this exact URL.\n\n- `domain?: string`\n Domain name to take screenshot of (e.g., 'example.com', 'google.com'). The domain will be automatically normalized and validated.\n\n- `fullScreenshot?: 'true' | 'false'`\n Optional parameter to determine screenshot type. If 'true', takes a full page screenshot capturing all content. If 'false' or not provided, takes a viewport screenshot (standard browser view).\n\n- `page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact'`\n Optional parameter to specify which page type to screenshot. If provided, the system will scrape the domain's links and use heuristics to find the most appropriate URL for the specified page type (30 supported languages). If not provided, screenshots the main domain landing page. Only applicable when using 'domain', not 'directUrl'.\n\n- `prioritize?: 'speed' | 'quality'`\n Optional parameter to prioritize screenshot capture. If 'speed', optimizes for faster capture with basic quality. If 'quality', optimizes for higher quality with longer wait times. Defaults to 'quality' if not provided.\n\n### Returns\n\n- `{ code?: number; domain?: string; screenshot?: string; screenshotType?: 'viewport' | 'fullPage'; status?: string; }`\n\n - `code?: number`\n - `domain?: string`\n - `screenshot?: string`\n - `screenshotType?: 'viewport' | 'fullPage'`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.screenshot();\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -592,22 +593,22 @@ const EMBEDDED_METHODS: MethodEntry[] = [ java: { method: 'brand().screenshot', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandScreenshotParams;\nimport com.branddev.api.models.brand.BrandScreenshotResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandScreenshotParams params = BrandScreenshotParams.builder()\n .domain("domain")\n .build();\n BrandScreenshotResponse response = client.brand().screenshot(params);\n }\n}', + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandScreenshotParams;\nimport com.branddev.api.models.brand.BrandScreenshotResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandScreenshotResponse response = client.brand().screenshot();\n }\n}', }, python: { method: 'brand.screenshot', example: - 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.screenshot(\n domain="domain",\n)\nprint(response.code)', + 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.screenshot()\nprint(response.code)', }, ruby: { method: 'brand.screenshot', example: - 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.screenshot(domain: "domain")\n\nputs(response)', + 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.screenshot\n\nputs(response)', }, typescript: { method: 'client.brand.screenshot', example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.screenshot({ domain: 'domain' });\n\nconsole.log(response.code);", + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.screenshot();\n\nconsole.log(response.code);", }, }, }, diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 8c35602b..33039eae 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -156,10 +156,14 @@ export class Brand extends APIResource { /** * Capture a screenshot of a website. Supports both viewport (standard browser * view) and full-page screenshots. Can also screenshot specific page types (login, - * pricing, etc.) by using heuristics to find the appropriate URL. Returns a URL to - * the uploaded screenshot image hosted on our CDN. + * pricing, etc.) by using heuristics to find the appropriate URL. Either 'domain' + * or 'directUrl' must be provided as a query parameter, but not both. Returns a + * URL to the uploaded screenshot image hosted on our CDN. */ - screenshot(query: BrandScreenshotParams, options?: RequestOptions): APIPromise { + screenshot( + query: BrandScreenshotParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { return this._client.get('/brand/screenshot', { query, ...options }); } @@ -7634,11 +7638,18 @@ export interface BrandRetrieveSimplifiedParams { } export interface BrandScreenshotParams { + /** + * A specific URL to screenshot directly, bypassing domain resolution (e.g., + * 'https://example.com/pricing'). When provided, the screenshot is taken of this + * exact URL. + */ + directUrl?: string; + /** * Domain name to take screenshot of (e.g., 'example.com', 'google.com'). The * domain will be automatically normalized and validated. */ - domain: string; + domain?: string; /** * Optional parameter to determine screenshot type. If 'true', takes a full page @@ -7651,7 +7662,8 @@ export interface BrandScreenshotParams { * Optional parameter to specify which page type to screenshot. If provided, the * system will scrape the domain's links and use heuristics to find the most * appropriate URL for the specified page type (30 supported languages). If not - * provided, screenshots the main domain landing page. + * provided, screenshots the main domain landing page. Only applicable when using + * 'domain', not 'directUrl'. */ page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact'; diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 117f656e..91a56a7c 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -327,8 +327,8 @@ describe('resource brand', () => { }); // Mock server tests are disabled - test.skip('screenshot: only required params', async () => { - const responsePromise = client.brand.screenshot({ domain: 'domain' }); + test.skip('screenshot', async () => { + const responsePromise = client.brand.screenshot(); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -339,13 +339,20 @@ describe('resource brand', () => { }); // Mock server tests are disabled - test.skip('screenshot: required and optional params', async () => { - const response = await client.brand.screenshot({ - domain: 'domain', - fullScreenshot: 'true', - page: 'login', - prioritize: 'speed', - }); + test.skip('screenshot: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.brand.screenshot( + { + directUrl: 'https://example.com', + domain: 'domain', + fullScreenshot: 'true', + page: 'login', + prioritize: 'speed', + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(BrandDev.NotFoundError); }); // Mock server tests are disabled From bdc35636b0866d6daecd3be434a46989776fe53f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 08:46:21 +0000 Subject: [PATCH 008/100] chore(internal): show error causes in MCP servers when running in local mode --- packages/mcp-server/src/code-tool-worker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts index b95cc961..2524f5a4 100644 --- a/packages/mcp-server/src/code-tool-worker.ts +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -204,7 +204,8 @@ function makeSdkProxy(obj: T, { path, isBelievedBad = false }: function parseError(code: string, error: unknown): string | undefined { if (!(error instanceof Error)) return; - const message = error.name ? `${error.name}: ${error.message}` : error.message; + const cause = error.cause instanceof Error ? `: ${error.cause.message}` : ''; + const message = error.name ? `${error.name}: ${error.message}${cause}` : `${error.message}${cause}`; try { // Deno uses V8; the first ":LINE:COLUMN" is the top of stack. const lineNumber = error.stack?.match(/:([0-9]+):[0-9]+/)?.[1]; From fbf38850134f41f8c5c3ffb7688654ca4c01b72e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 15:54:30 +0000 Subject: [PATCH 009/100] feat(api): api update --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index e5e2a93b..f6eae3cd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1220,9 +1220,9 @@ baseline-browser-mapping@^2.9.0: integrity sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg== brace-expansion@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.3.tgz#0493338bdd58e319b1039c67cf7ee439892c01d9" - integrity sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA== + version "2.1.0" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.0.tgz#4f41a41190216ee36067ec381526fe9539c4f0ae" + integrity sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w== dependencies: balanced-match "^1.0.0" From e52e3bd257093f73507b287f9bcb0c6609db4c94 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 12 Apr 2026 14:44:27 +0000 Subject: [PATCH 010/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 97c1cfd7..f82697e3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-905e35387d755a84a2e7cd711f31eeea130e08a83bb7b39d3fa5445a187ef62f.yml -openapi_spec_hash: 205b2c17cb40ad54d76c2c06c9e5dda4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-40b1d672fe922d8157775c48539332de9a8bff757a174db394ec5f1e3968678b.yml +openapi_spec_hash: ae60ee9eafb3bcb77ba255818e7d228d config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 8a6f5f37e39c9154eb632457e85f9b5963923078 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 12 Apr 2026 14:53:24 +0000 Subject: [PATCH 011/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f82697e3..4f2e69a4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-40b1d672fe922d8157775c48539332de9a8bff757a174db394ec5f1e3968678b.yml -openapi_spec_hash: ae60ee9eafb3bcb77ba255818e7d228d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-0b41a16de26363ad6880dc82a92a24f4c44b5cd8435344720383619d6019e792.yml +openapi_spec_hash: fc92550089eb09bd802e4178bbde83c0 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 1aa23d2d2405770b31805a7f1ad67a1cae26bb2a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 12 Apr 2026 14:58:29 +0000 Subject: [PATCH 012/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4f2e69a4..b49f2b4a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-0b41a16de26363ad6880dc82a92a24f4c44b5cd8435344720383619d6019e792.yml -openapi_spec_hash: fc92550089eb09bd802e4178bbde83c0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-57f28dde4f89132b3ad99235eb8940391a3f6756c2fd0eafe4e2a0615aa32d50.yml +openapi_spec_hash: d7771a48eb4480cb0868d3af901fe360 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 024a446f3f10deedeca23840cf704f6d6383684a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 12 Apr 2026 21:16:26 +0000 Subject: [PATCH 013/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b49f2b4a..2eee2eae 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-57f28dde4f89132b3ad99235eb8940391a3f6756c2fd0eafe4e2a0615aa32d50.yml -openapi_spec_hash: d7771a48eb4480cb0868d3af901fe360 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-4876a8799d99d7b497a352f6b873e53cff8b98019d4070e65fd272eed87ccda4.yml +openapi_spec_hash: c095133c2695510842b84cf5820a16a4 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From d3ddae876866735ed1d74b606b13e3904aaaea73 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 14:43:20 +0000 Subject: [PATCH 014/100] feat(api): api update --- .stats.yml | 4 +-- packages/mcp-server/src/local-docs-search.ts | 4 +-- src/resources/brand.ts | 30 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2eee2eae..9b7576d8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-4876a8799d99d7b497a352f6b873e53cff8b98019d4070e65fd272eed87ccda4.yml -openapi_spec_hash: c095133c2695510842b84cf5820a16a4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-e7d0d9b555ca50f58e651f918238ee1329755f46cb962feaedec097be4c28d83.yml +openapi_spec_hash: b187dde21c352dd66cf249fbc14dd0b4 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index a9512562..75bc38b9 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -535,9 +535,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.styleguide', params: ['directUrl?: string;', 'domain?: string;', 'timeoutMS?: number;'], response: - "{ code?: number; domain?: string; status?: string; styleguide?: { colors: { accent: string; background: string; text: string; }; components: { button: object; card?: object; }; elementSpacing: { lg: string; md: string; sm: string; xl: string; xs: string; }; mode: 'light' | 'dark'; shadows: { inner: string; lg: string; md: string; sm: string; xl: string; }; typography: { headings: object; p?: object; }; }; }", + "{ code?: number; domain?: string; status?: string; styleguide?: { colors: { accent: string; background: string; text: string; }; components: { button: object; card?: object; }; elementSpacing: { lg: string; md: string; sm: string; xl: string; xs: string; }; fontLinks: object; mode: 'light' | 'dark'; shadows: { inner: string; lg: string; md: string; sm: string; xl: string; }; typography: { headings: object; p?: object; }; }; }", markdown: - "## styleguide\n\n`client.brand.styleguide(directUrl?: string, domain?: string, timeoutMS?: number): { code?: number; domain?: string; status?: string; styleguide?: object; }`\n\n**get** `/brand/styleguide`\n\nAutomatically extract comprehensive design system information from a brand's website including colors, typography, spacing, shadows, and UI components. Either 'domain' or 'directUrl' must be provided as a query parameter, but not both.\n\n### Parameters\n\n- `directUrl?: string`\n A specific URL to fetch the styleguide from directly, bypassing domain resolution (e.g., 'https://example.com/design-system').\n\n- `domain?: string`\n Domain name to extract styleguide from (e.g., 'example.com', 'google.com'). The domain will be automatically normalized and validated.\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- `{ code?: number; domain?: string; status?: string; styleguide?: { colors: { accent: string; background: string; text: string; }; components: { button: object; card?: object; }; elementSpacing: { lg: string; md: string; sm: string; xl: string; xs: string; }; mode: 'light' | 'dark'; shadows: { inner: string; lg: string; md: string; sm: string; xl: string; }; typography: { headings: object; p?: object; }; }; }`\n\n - `code?: number`\n - `domain?: string`\n - `status?: string`\n - `styleguide?: { colors: { accent: string; background: string; text: string; }; components: { button: { link?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; color: string; css: string; fontSize: string; fontWeight: number; minHeight: string; minWidth: string; padding: string; textDecoration: string; fontFallbacks?: string[]; fontFamily?: string; textDecorationColor?: string; }; primary?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; color: string; css: string; fontSize: string; fontWeight: number; minHeight: string; minWidth: string; padding: string; textDecoration: string; fontFallbacks?: string[]; fontFamily?: string; textDecorationColor?: string; }; secondary?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; color: string; css: string; fontSize: string; fontWeight: number; minHeight: string; minWidth: string; padding: string; textDecoration: string; fontFallbacks?: string[]; fontFamily?: string; textDecorationColor?: string; }; }; card?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; css: string; padding: string; textColor: string; }; }; elementSpacing: { lg: string; md: string; sm: string; xl: string; xs: string; }; mode: 'light' | 'dark'; shadows: { inner: string; lg: string; md: string; sm: string; xl: string; }; typography: { headings: { h1?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; h2?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; h3?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; h4?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; }; p?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; }; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.styleguide();\n\nconsole.log(response);\n```", + "## styleguide\n\n`client.brand.styleguide(directUrl?: string, domain?: string, timeoutMS?: number): { code?: number; domain?: string; status?: string; styleguide?: object; }`\n\n**get** `/brand/styleguide`\n\nAutomatically extract comprehensive design system information from a brand's website including colors, typography, spacing, shadows, and UI components. Either 'domain' or 'directUrl' must be provided as a query parameter, but not both.\n\n### Parameters\n\n- `directUrl?: string`\n A specific URL to fetch the styleguide from directly, bypassing domain resolution (e.g., 'https://example.com/design-system').\n\n- `domain?: string`\n Domain name to extract styleguide from (e.g., 'example.com', 'google.com'). The domain will be automatically normalized and validated.\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- `{ code?: number; domain?: string; status?: string; styleguide?: { colors: { accent: string; background: string; text: string; }; components: { button: object; card?: object; }; elementSpacing: { lg: string; md: string; sm: string; xl: string; xs: string; }; fontLinks: object; mode: 'light' | 'dark'; shadows: { inner: string; lg: string; md: string; sm: string; xl: string; }; typography: { headings: object; p?: object; }; }; }`\n\n - `code?: number`\n - `domain?: string`\n - `status?: string`\n - `styleguide?: { colors: { accent: string; background: string; text: string; }; components: { button: { link?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; color: string; css: string; fontSize: string; fontWeight: number; minHeight: string; minWidth: string; padding: string; textDecoration: string; fontFallbacks?: string[]; fontFamily?: string; textDecorationColor?: string; }; primary?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; color: string; css: string; fontSize: string; fontWeight: number; minHeight: string; minWidth: string; padding: string; textDecoration: string; fontFallbacks?: string[]; fontFamily?: string; textDecorationColor?: string; }; secondary?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; color: string; css: string; fontSize: string; fontWeight: number; minHeight: string; minWidth: string; padding: string; textDecoration: string; fontFallbacks?: string[]; fontFamily?: string; textDecorationColor?: string; }; }; card?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; css: string; padding: string; textColor: string; }; }; elementSpacing: { lg: string; md: string; sm: string; xl: string; xs: string; }; fontLinks: object; mode: 'light' | 'dark'; shadows: { inner: string; lg: string; md: string; sm: string; xl: string; }; typography: { headings: { h1?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; h2?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; h3?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; h4?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; }; p?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; }; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.styleguide();\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 33039eae..ca3f5504 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -5349,6 +5349,13 @@ export namespace BrandStyleguideResponse { */ elementSpacing: Styleguide.ElementSpacing; + /** + * Font assets keyed by family name as it appears in fontFamily/fontFallbacks + * (non-generic names only). Clients match typography.fontFamily / fontWeight or + * button styles to pick a file URL from files. + */ + fontLinks: { [key: string]: Styleguide.FontLinks }; + /** * The primary color mode of the website design */ @@ -5644,6 +5651,29 @@ export namespace BrandStyleguideResponse { xs: string; } + export interface FontLinks { + /** + * Upright font files keyed by weight string (e.g. "400" for regular, "500", + * "700"). Values are absolute URLs. + */ + files: { [key: string]: string }; + + type: 'google' | 'custom'; + + /** + * Google Fonts category when type is google (e.g. sans-serif, serif, monospace, + * display, handwriting). Omitted for custom fonts when unknown. + */ + category?: string; + + /** + * Present when type is custom: human-readable name derived from the fontLinks key + * (strip build/hash suffixes, split camelCase / PascalCase, normalize separators). + * Google entries omit this. + */ + displayName?: string; + } + /** * Shadow styles used on the website */ From eddea3f1a05a07b311c01ba7d63c5ea8006a6007 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 01:19:43 +0000 Subject: [PATCH 015/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 7 ++++--- src/resources/brand.ts | 14 ++++++++++++++ tests/api-resources/brand.test.ts | 3 ++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9b7576d8..41aba4a2 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-e7d0d9b555ca50f58e651f918238ee1329755f46cb962feaedec097be4c28d83.yml -openapi_spec_hash: b187dde21c352dd66cf249fbc14dd0b4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-4bc00d073aa6c38b3299c9fc2e197ba9e25df5defca2508a0a0c83bf08237b00.yml +openapi_spec_hash: b68c73667402fd727825555413522ce6 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 75bc38b9..a012ec81 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -743,10 +743,10 @@ const EMBEDDED_METHODS: MethodEntry[] = [ description: 'Scrapes the given URL and returns the raw HTML content of the page.', stainlessPath: '(resource) brand > (method) web_scrape_html', qualified: 'client.brand.webScrapeHTML', - params: ['url: string;'], + params: ['url: string;', 'maxAgeMs?: number;'], response: '{ html: string; success: true; url: string; }', markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, maxAgeMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\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. Set to 0 to always scrape fresh.\n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -786,12 +786,13 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'url: string;', 'includeImages?: boolean;', 'includeLinks?: boolean;', + 'maxAgeMs?: number;', 'shortenBase64Images?: boolean;', 'useMainContentOnly?: boolean;', ], response: '{ markdown: string; success: true; url: string; }', markdown: - "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeImages?: boolean, includeLinks?: boolean, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL, converts the HTML content to Markdown, and returns the result.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape and convert to markdown (must include http:// or https:// protocol)\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL, converts the HTML content to Markdown, and returns the result.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape and convert to markdown (must include http:// or https:// protocol)\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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. Set to 0 to always scrape fresh.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index ca3f5504..a5bf2901 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -7731,6 +7731,13 @@ export interface BrandWebScrapeHTMLParams { * Full URL to scrape (must include http:// or https:// protocol) */ url: string; + + /** + * 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. Set to 0 to always scrape fresh. + */ + maxAgeMs?: number; } export interface BrandWebScrapeImagesParams { @@ -7757,6 +7764,13 @@ export interface BrandWebScrapeMdParams { */ includeLinks?: boolean; + /** + * 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. Set to 0 to always scrape fresh. + */ + maxAgeMs?: number; + /** * Shorten base64-encoded image data in the Markdown output */ diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 91a56a7c..42651ddc 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -396,7 +396,7 @@ describe('resource brand', () => { // Mock server tests are disabled test.skip('webScrapeHTML: required and optional params', async () => { - const response = await client.brand.webScrapeHTML({ url: 'https://example.com' }); + const response = await client.brand.webScrapeHTML({ url: 'https://example.com', maxAgeMs: 0 }); }); // Mock server tests are disabled @@ -434,6 +434,7 @@ describe('resource brand', () => { url: 'https://example.com', includeImages: true, includeLinks: true, + maxAgeMs: 0, shortenBase64Images: true, useMainContentOnly: true, }); From 4b26b8765fbe347c55159e6a3b98cd26c1f2a478 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 01:36:15 +0000 Subject: [PATCH 016/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 4 ++-- src/resources/brand.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 41aba4a2..4caa3eb3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-4bc00d073aa6c38b3299c9fc2e197ba9e25df5defca2508a0a0c83bf08237b00.yml -openapi_spec_hash: b68c73667402fd727825555413522ce6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-f15e63fe284d980e63fbbba5b3f845f91565f43e4c0b3182bb5d8bd55fda2a51.yml +openapi_spec_hash: 5f833c91cc4541722b10451a4629c1bc config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index a012ec81..417e1870 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -739,14 +739,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ name: 'web_scrape_html', endpoint: '/web/scrape/html', httpMethod: 'get', - summary: 'Scrape raw HTML from a URL', + summary: 'Scrape HTML', description: 'Scrapes the given URL and returns the raw HTML content of the page.', stainlessPath: '(resource) brand > (method) web_scrape_html', qualified: 'client.brand.webScrapeHTML', params: ['url: string;', 'maxAgeMs?: number;'], response: '{ html: string; success: true; url: string; }', markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, maxAgeMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\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. Set to 0 to always scrape fresh.\n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, maxAgeMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\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### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index a5bf2901..f440696f 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -7735,7 +7735,7 @@ export interface BrandWebScrapeHTMLParams { /** * 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. Set to 0 to always scrape fresh. + * omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh. */ maxAgeMs?: number; } From 5819866293d5d87b22457a7d0f2412a726788e97 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 01:44:32 +0000 Subject: [PATCH 017/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 6 +++--- src/resources/brand.ts | 7 +++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4caa3eb3..792fcdf1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-f15e63fe284d980e63fbbba5b3f845f91565f43e4c0b3182bb5d8bd55fda2a51.yml -openapi_spec_hash: 5f833c91cc4541722b10451a4629c1bc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-93cf699701172f25e4f6d5053b0573eeb51a79707de94a137ac23d0aaeb76e36.yml +openapi_spec_hash: 4abd14fccd70b0cb0397776e6b5b9171 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 417e1870..6cad233b 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -778,8 +778,8 @@ const EMBEDDED_METHODS: MethodEntry[] = [ name: 'web_scrape_md', endpoint: '/web/scrape/markdown', httpMethod: 'get', - summary: 'Scrape URL and convert to Markdown', - description: 'Scrapes the given URL, converts the HTML content to Markdown, and returns the result.', + summary: 'Scrape Markdown', + description: 'Scrapes the given URL into LLM usable Markdown.', stainlessPath: '(resource) brand > (method) web_scrape_md', qualified: 'client.brand.webScrapeMd', params: [ @@ -792,7 +792,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ ], response: '{ markdown: string; success: true; url: string; }', markdown: - "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL, converts the HTML content to Markdown, and returns the result.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape and convert to markdown (must include http:// or https:// protocol)\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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. Set to 0 to always scrape fresh.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index f440696f..47696a72 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -203,8 +203,7 @@ export class Brand extends APIResource { } /** - * Scrapes the given URL, converts the HTML content to Markdown, and returns the - * result. + * Scrapes the given URL into LLM usable Markdown. */ webScrapeMd(query: BrandWebScrapeMdParams, options?: RequestOptions): APIPromise { return this._client.get('/web/scrape/markdown', { query, ...options }); @@ -7749,7 +7748,7 @@ export interface BrandWebScrapeImagesParams { export interface BrandWebScrapeMdParams { /** - * Full URL to scrape and convert to markdown (must include http:// or https:// + * Full URL to scrape into LLM usable Markdown (must include http:// or https:// * protocol) */ url: string; @@ -7767,7 +7766,7 @@ export interface BrandWebScrapeMdParams { /** * 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. Set to 0 to always scrape fresh. + * omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh. */ maxAgeMs?: number; From d7028891158c4821acd11093fc69172b9f591db3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 01:55:53 +0000 Subject: [PATCH 018/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 792fcdf1..0e03d0e7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-93cf699701172f25e4f6d5053b0573eeb51a79707de94a137ac23d0aaeb76e36.yml -openapi_spec_hash: 4abd14fccd70b0cb0397776e6b5b9171 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-e1e6c71c933578dccc0c110054a5fa21347c4795dff14fd48f5873536b4ce959.yml +openapi_spec_hash: 12b5773c2b15c2f7cdce7590237a1125 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 6cad233b..e5edfc80 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -824,7 +824,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ name: 'web_scrape_images', endpoint: '/web/scrape/images', httpMethod: 'get', - summary: 'Scrape images from a URL', + summary: 'Scrape Images', description: 'Scrapes all images from the given URL. Extracts images from img, svg, picture/source, link, and video elements including inline SVGs, base64 data URIs, and standard URLs.', stainlessPath: '(resource) brand > (method) web_scrape_images', From 85a4faddcc76130685e7d683999dc2712ce388a9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 02:07:06 +0000 Subject: [PATCH 019/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 7 +++---- src/resources/brand.ts | 7 ++----- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0e03d0e7..ec6d2505 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-e1e6c71c933578dccc0c110054a5fa21347c4795dff14fd48f5873536b4ce959.yml -openapi_spec_hash: 12b5773c2b15c2f7cdce7590237a1125 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-2a7727122f4ea5f9240c4c701f70f91b48f861bf5d87ec64f6904d635be5aef8.yml +openapi_spec_hash: 51884daf875aba2f255aaaf69ef1c42d config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index e5edfc80..73fa97b2 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -865,16 +865,15 @@ const EMBEDDED_METHODS: MethodEntry[] = [ name: 'web_scrape_sitemap', endpoint: '/web/scrape/sitemap', httpMethod: 'get', - summary: 'Crawl website sitemap', - description: - 'Crawls the sitemap of the given domain and returns all discovered page URLs. Supports sitemap index files (recursive), parallel fetching with concurrency control, deduplication, and filters out non-page resources (images, PDFs, etc.).', + summary: 'Crawl Sitemap', + description: "Crawl an entire website's sitemap and return all discovered page URLs", stainlessPath: '(resource) brand > (method) web_scrape_sitemap', qualified: 'client.brand.webScrapeSitemap', params: ['domain: string;', 'maxLinks?: number;'], response: '{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }', markdown: - "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawls the sitemap of the given domain and returns all discovered page URLs. Supports sitemap index files (recursive), parallel fetching with concurrency control, deduplication, and filters out non-page resources (images, PDFs, etc.).\n\n### Parameters\n\n- `domain: string`\n Domain name to crawl sitemaps for (e.g., 'example.com'). The domain will be automatically normalized and validated.\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 47696a72..2bd24baa 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -210,9 +210,7 @@ export class Brand extends APIResource { } /** - * Crawls the sitemap of the given domain and returns all discovered page URLs. - * Supports sitemap index files (recursive), parallel fetching with concurrency - * control, deduplication, and filters out non-page resources (images, PDFs, etc.). + * Crawl an entire website's sitemap and return all discovered page URLs */ webScrapeSitemap( query: BrandWebScrapeSitemapParams, @@ -7784,8 +7782,7 @@ export interface BrandWebScrapeMdParams { export interface BrandWebScrapeSitemapParams { /** - * Domain name to crawl sitemaps for (e.g., 'example.com'). The domain will be - * automatically normalized and validated. + * Domain to build a sitemap for */ domain: string; From bdf98535098476c0362d88a9ceff962edd5aafae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 02:17:54 +0000 Subject: [PATCH 020/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ec6d2505..ff47fd44 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-2a7727122f4ea5f9240c4c701f70f91b48f861bf5d87ec64f6904d635be5aef8.yml -openapi_spec_hash: 51884daf875aba2f255aaaf69ef1c42d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-a3f9cb65527955359bd08122edd68527fb13d5ba8fa8279fb3892e277e1d6233.yml +openapi_spec_hash: 037b592f3b2373d9b0753ba5b7d571b5 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From e51ec781fdbbd8751932167a817714f3408e916a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 02:24:55 +0000 Subject: [PATCH 021/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ff47fd44..3e31f1c0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-a3f9cb65527955359bd08122edd68527fb13d5ba8fa8279fb3892e277e1d6233.yml -openapi_spec_hash: 037b592f3b2373d9b0753ba5b7d571b5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-41fdbb36b66c713e8073c04937010aa4b861a99b105966856e211c9aaee1fe34.yml +openapi_spec_hash: daadd24dfc43587bb323a137089edd7d config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 7fae62af58b8ebc012fd23e39d09ab939b1bd309 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 21:56:10 +0000 Subject: [PATCH 022/100] feat(api): api update --- .stats.yml | 6 +- api.md | 2 - packages/mcp-server/src/code-tool-worker.ts | 1 - packages/mcp-server/src/local-docs-search.ts | 41 ---------- packages/mcp-server/src/methods.ts | 6 -- src/client.ts | 4 - src/resources/brand.ts | 86 -------------------- src/resources/index.ts | 2 - tests/api-resources/brand.test.ts | 17 ---- 9 files changed, 3 insertions(+), 162 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3e31f1c0..c1176570 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-41fdbb36b66c713e8073c04937010aa4b861a99b105966856e211c9aaee1fe34.yml -openapi_spec_hash: daadd24dfc43587bb323a137089edd7d +configured_endpoints: 19 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-135cee98ff73868b77c6dd17f5d1ccc7cd1e26a8cef266ceba1020346e11a8ef.yml +openapi_spec_hash: d9c1751a0fd999118b6d55d4931212e1 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/api.md b/api.md index 1bdf5b06..6a320674 100644 --- a/api.md +++ b/api.md @@ -6,7 +6,6 @@ Types: - BrandAIProductResponse - BrandAIProductsResponse - BrandAIQueryResponse -- BrandFontsResponse - BrandIdentifyFromTransactionResponse - BrandPrefetchResponse - BrandPrefetchByEmailResponse @@ -29,7 +28,6 @@ Methods: - client.brand.aiProduct({ ...params }) -> BrandAIProductResponse - client.brand.aiProducts({ ...params }) -> BrandAIProductsResponse - client.brand.aiQuery({ ...params }) -> BrandAIQueryResponse -- client.brand.fonts({ ...params }) -> BrandFontsResponse - client.brand.identifyFromTransaction({ ...params }) -> BrandIdentifyFromTransactionResponse - client.brand.prefetch({ ...params }) -> BrandPrefetchResponse - client.brand.prefetchByEmail({ ...params }) -> BrandPrefetchByEmailResponse diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts index 2524f5a4..f0654dd9 100644 --- a/packages/mcp-server/src/code-tool-worker.ts +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -111,7 +111,6 @@ const fuse = new Fuse( 'client.brand.aiProduct', 'client.brand.aiProducts', 'client.brand.aiQuery', - 'client.brand.fonts', 'client.brand.identifyFromTransaction', 'client.brand.prefetch', 'client.brand.prefetchByEmail', diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 73fa97b2..55210d50 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -612,47 +612,6 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, }, }, - { - name: 'fonts', - endpoint: '/brand/fonts', - httpMethod: 'get', - summary: 'Extract fonts from website', - description: - "Extract font information from a brand's website including font families, usage statistics, fallbacks, and element/word counts.", - stainlessPath: '(resource) brand > (method) fonts', - qualified: 'client.brand.fonts', - params: ['domain: string;', 'timeoutMS?: number;'], - response: - '{ code: number; domain: string; fonts: { fallbacks: string[]; font: string; num_elements: number; num_words: number; percent_elements: number; percent_words: number; uses: string[]; }[]; status: string; }', - markdown: - "## fonts\n\n`client.brand.fonts(domain: string, timeoutMS?: number): { code: number; domain: string; fonts: object[]; status: string; }`\n\n**get** `/brand/fonts`\n\nExtract font information from a brand's website including font families, usage statistics, fallbacks, and element/word counts.\n\n### Parameters\n\n- `domain: string`\n Domain name to extract fonts from (e.g., 'example.com', 'google.com'). The domain will be automatically normalized and validated.\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- `{ code: number; domain: string; fonts: { fallbacks: string[]; font: string; num_elements: number; num_words: number; percent_elements: number; percent_words: number; uses: string[]; }[]; status: string; }`\n\n - `code: number`\n - `domain: string`\n - `fonts: { fallbacks: string[]; font: string; num_elements: number; num_words: number; percent_elements: number; percent_words: number; uses: string[]; }[]`\n - `status: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.fonts({ domain: 'domain' });\n\nconsole.log(response);\n```", - perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/fonts \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().fonts', - example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandFontsParams;\nimport com.branddev.api.models.brand.BrandFontsResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandFontsParams params = BrandFontsParams.builder()\n .domain("domain")\n .build();\n BrandFontsResponse response = client.brand().fonts(params);\n }\n}', - }, - python: { - method: 'brand.fonts', - example: - 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.fonts(\n domain="domain",\n)\nprint(response.code)', - }, - ruby: { - method: 'brand.fonts', - example: - 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.fonts(domain: "domain")\n\nputs(response)', - }, - typescript: { - method: 'client.brand.fonts', - example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.fonts({ domain: 'domain' });\n\nconsole.log(response.code);", - }, - }, - }, { name: 'ai_products', endpoint: '/brand/ai/products', diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts index c5ab8ae0..909c9f5f 100644 --- a/packages/mcp-server/src/methods.ts +++ b/packages/mcp-server/src/methods.ts @@ -34,12 +34,6 @@ export const sdkMethods: SdkMethod[] = [ httpMethod: 'post', httpPath: '/brand/ai/query', }, - { - clientCallName: 'client.brand.fonts', - fullyQualifiedName: 'brand.fonts', - httpMethod: 'get', - httpPath: '/brand/fonts', - }, { clientCallName: 'client.brand.identifyFromTransaction', fullyQualifiedName: 'brand.identifyFromTransaction', diff --git a/src/client.ts b/src/client.ts index 59d68ebd..1ba255fb 100644 --- a/src/client.ts +++ b/src/client.ts @@ -25,8 +25,6 @@ import { BrandAIProductsResponse, BrandAIQueryParams, BrandAIQueryResponse, - BrandFontsParams, - BrandFontsResponse, BrandIdentifyFromTransactionParams, BrandIdentifyFromTransactionResponse, BrandPrefetchByEmailParams, @@ -774,7 +772,6 @@ export declare namespace BrandDev { type BrandAIProductResponse as BrandAIProductResponse, type BrandAIProductsResponse as BrandAIProductsResponse, type BrandAIQueryResponse as BrandAIQueryResponse, - type BrandFontsResponse as BrandFontsResponse, type BrandIdentifyFromTransactionResponse as BrandIdentifyFromTransactionResponse, type BrandPrefetchResponse as BrandPrefetchResponse, type BrandPrefetchByEmailResponse as BrandPrefetchByEmailResponse, @@ -794,7 +791,6 @@ export declare namespace BrandDev { type BrandAIProductParams as BrandAIProductParams, type BrandAIProductsParams as BrandAIProductsParams, type BrandAIQueryParams as BrandAIQueryParams, - type BrandFontsParams as BrandFontsParams, type BrandIdentifyFromTransactionParams as BrandIdentifyFromTransactionParams, type BrandPrefetchParams as BrandPrefetchParams, type BrandPrefetchByEmailParams as BrandPrefetchByEmailParams, diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 2bd24baa..4a1c0bab 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -40,14 +40,6 @@ export class Brand extends APIResource { return this._client.post('/brand/ai/query', { body, ...options }); } - /** - * Extract font information from a brand's website including font families, usage - * statistics, fallbacks, and element/word counts. - */ - fonts(query: BrandFontsParams, options?: RequestOptions): APIPromise { - return this._client.get('/brand/fonts', { query, ...options }); - } - /** * Endpoint specially designed for platforms that want to identify transaction data * by the transaction title. @@ -1179,67 +1171,6 @@ export namespace BrandAIQueryResponse { } } -export interface BrandFontsResponse { - /** - * HTTP status code, e.g., 200 - */ - code: number; - - /** - * The normalized domain that was processed - */ - domain: string; - - /** - * Array of font usage information - */ - fonts: Array; - - /** - * Status of the response, e.g., 'ok' - */ - status: string; -} - -export namespace BrandFontsResponse { - export interface Font { - /** - * Array of fallback font families - */ - fallbacks: Array; - - /** - * Font family name - */ - font: string; - - /** - * Number of elements using this font - */ - num_elements: number; - - /** - * Number of words using this font - */ - num_words: number; - - /** - * Percentage of elements using this font - */ - percent_elements: number; - - /** - * Percentage of words using this font - */ - percent_words: number; - - /** - * Array of CSS selectors or element types where this font is used - */ - uses: Array; - } -} - export interface BrandIdentifyFromTransactionResponse { /** * Detailed brand information @@ -6252,21 +6183,6 @@ export namespace BrandAIQueryParams { } } -export interface BrandFontsParams { - /** - * Domain name to extract fonts from (e.g., 'example.com', 'google.com'). The - * domain will be automatically normalized and validated. - */ - domain: string; - - /** - * 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). - */ - timeoutMS?: number; -} - export interface BrandIdentifyFromTransactionParams { /** * Transaction information to identify the brand @@ -7799,7 +7715,6 @@ export declare namespace Brand { type BrandAIProductResponse as BrandAIProductResponse, type BrandAIProductsResponse as BrandAIProductsResponse, type BrandAIQueryResponse as BrandAIQueryResponse, - type BrandFontsResponse as BrandFontsResponse, type BrandIdentifyFromTransactionResponse as BrandIdentifyFromTransactionResponse, type BrandPrefetchResponse as BrandPrefetchResponse, type BrandPrefetchByEmailResponse as BrandPrefetchByEmailResponse, @@ -7819,7 +7734,6 @@ export declare namespace Brand { type BrandAIProductParams as BrandAIProductParams, type BrandAIProductsParams as BrandAIProductsParams, type BrandAIQueryParams as BrandAIQueryParams, - type BrandFontsParams as BrandFontsParams, type BrandIdentifyFromTransactionParams as BrandIdentifyFromTransactionParams, type BrandPrefetchParams as BrandPrefetchParams, type BrandPrefetchByEmailParams as BrandPrefetchByEmailParams, diff --git a/src/resources/index.ts b/src/resources/index.ts index 7031f6b7..798b703a 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -6,7 +6,6 @@ export { type BrandAIProductResponse, type BrandAIProductsResponse, type BrandAIQueryResponse, - type BrandFontsResponse, type BrandIdentifyFromTransactionResponse, type BrandPrefetchResponse, type BrandPrefetchByEmailResponse, @@ -26,7 +25,6 @@ export { type BrandAIProductParams, type BrandAIProductsParams, type BrandAIQueryParams, - type BrandFontsParams, type BrandIdentifyFromTransactionParams, type BrandPrefetchParams, type BrandPrefetchByEmailParams, diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 42651ddc..3f7c2d22 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -119,23 +119,6 @@ describe('resource brand', () => { }); }); - // Mock server tests are disabled - test.skip('fonts: only required params', async () => { - const responsePromise = client.brand.fonts({ domain: 'domain' }); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); - - // Mock server tests are disabled - test.skip('fonts: required and optional params', async () => { - const response = await client.brand.fonts({ domain: 'domain', timeoutMS: 1000 }); - }); - // Mock server tests are disabled test.skip('identifyFromTransaction: only required params', async () => { const responsePromise = client.brand.identifyFromTransaction({ transaction_info: 'transaction_info' }); From 634a8eeec0cc6cf55fa66468c4e12edadfc8c222 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 22:17:24 +0000 Subject: [PATCH 023/100] feat(api): api update --- .stats.yml | 6 +- api.md | 2 - packages/mcp-server/src/code-tool-worker.ts | 1 - packages/mcp-server/src/local-docs-search.ts | 47 ------------ packages/mcp-server/src/methods.ts | 6 -- src/client.ts | 4 - src/resources/brand.ts | 81 -------------------- src/resources/index.ts | 2 - tests/api-resources/brand.test.ts | 29 ------- 9 files changed, 3 insertions(+), 175 deletions(-) diff --git a/.stats.yml b/.stats.yml index c1176570..0198e387 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 19 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-135cee98ff73868b77c6dd17f5d1ccc7cd1e26a8cef266ceba1020346e11a8ef.yml -openapi_spec_hash: d9c1751a0fd999118b6d55d4931212e1 +configured_endpoints: 18 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-73b75de3d3aae732e496f3828fc2c88711969e8abaae060d939da505f36cb3f8.yml +openapi_spec_hash: 30b5dacd44ef41592ba645033b3a1ca3 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/api.md b/api.md index 6a320674..9cc9196c 100644 --- a/api.md +++ b/api.md @@ -15,7 +15,6 @@ Types: - BrandRetrieveByTickerResponse - BrandRetrieveNaicsResponse - BrandRetrieveSimplifiedResponse -- BrandScreenshotResponse - BrandStyleguideResponse - BrandWebScrapeHTMLResponse - BrandWebScrapeImagesResponse @@ -37,7 +36,6 @@ Methods: - client.brand.retrieveByTicker({ ...params }) -> BrandRetrieveByTickerResponse - client.brand.retrieveNaics({ ...params }) -> BrandRetrieveNaicsResponse - client.brand.retrieveSimplified({ ...params }) -> BrandRetrieveSimplifiedResponse -- client.brand.screenshot({ ...params }) -> BrandScreenshotResponse - client.brand.styleguide({ ...params }) -> BrandStyleguideResponse - client.brand.webScrapeHTML({ ...params }) -> BrandWebScrapeHTMLResponse - client.brand.webScrapeImages({ ...params }) -> BrandWebScrapeImagesResponse diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts index f0654dd9..ffcb5e7f 100644 --- a/packages/mcp-server/src/code-tool-worker.ts +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -121,7 +121,6 @@ const fuse = new Fuse( 'client.brand.retrieveByTicker', 'client.brand.retrieveNaics', 'client.brand.retrieveSimplified', - 'client.brand.screenshot', 'client.brand.styleguide', 'client.brand.webScrapeHTML', 'client.brand.webScrapeImages', diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 55210d50..5844e469 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -565,53 +565,6 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, }, }, - { - name: 'screenshot', - endpoint: '/brand/screenshot', - httpMethod: 'get', - summary: 'Take screenshot of website', - description: - "Capture a screenshot of a website. Supports both viewport (standard browser view) and full-page screenshots. Can also screenshot specific page types (login, pricing, etc.) by using heuristics to find the appropriate URL. Either 'domain' or 'directUrl' must be provided as a query parameter, but not both. Returns a URL to the uploaded screenshot image hosted on our CDN.", - stainlessPath: '(resource) brand > (method) screenshot', - qualified: 'client.brand.screenshot', - params: [ - 'directUrl?: string;', - 'domain?: string;', - "fullScreenshot?: 'true' | 'false';", - "page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact';", - "prioritize?: 'speed' | 'quality';", - ], - response: - "{ code?: number; domain?: string; screenshot?: string; screenshotType?: 'viewport' | 'fullPage'; status?: string; }", - markdown: - "## screenshot\n\n`client.brand.screenshot(directUrl?: string, domain?: string, fullScreenshot?: 'true' | 'false', page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact', prioritize?: 'speed' | 'quality'): { code?: number; domain?: string; screenshot?: string; screenshotType?: 'viewport' | 'fullPage'; status?: string; }`\n\n**get** `/brand/screenshot`\n\nCapture a screenshot of a website. Supports both viewport (standard browser view) and full-page screenshots. Can also screenshot specific page types (login, pricing, etc.) by using heuristics to find the appropriate URL. Either 'domain' or 'directUrl' must be provided as a query parameter, but not both. Returns a URL to the uploaded screenshot image hosted on our CDN.\n\n### Parameters\n\n- `directUrl?: string`\n A specific URL to screenshot directly, bypassing domain resolution (e.g., 'https://example.com/pricing'). When provided, the screenshot is taken of this exact URL.\n\n- `domain?: string`\n Domain name to take screenshot of (e.g., 'example.com', 'google.com'). The domain will be automatically normalized and validated.\n\n- `fullScreenshot?: 'true' | 'false'`\n Optional parameter to determine screenshot type. If 'true', takes a full page screenshot capturing all content. If 'false' or not provided, takes a viewport screenshot (standard browser view).\n\n- `page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact'`\n Optional parameter to specify which page type to screenshot. If provided, the system will scrape the domain's links and use heuristics to find the most appropriate URL for the specified page type (30 supported languages). If not provided, screenshots the main domain landing page. Only applicable when using 'domain', not 'directUrl'.\n\n- `prioritize?: 'speed' | 'quality'`\n Optional parameter to prioritize screenshot capture. If 'speed', optimizes for faster capture with basic quality. If 'quality', optimizes for higher quality with longer wait times. Defaults to 'quality' if not provided.\n\n### Returns\n\n- `{ code?: number; domain?: string; screenshot?: string; screenshotType?: 'viewport' | 'fullPage'; status?: string; }`\n\n - `code?: number`\n - `domain?: string`\n - `screenshot?: string`\n - `screenshotType?: 'viewport' | 'fullPage'`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.screenshot();\n\nconsole.log(response);\n```", - perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/screenshot \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().screenshot', - example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandScreenshotParams;\nimport com.branddev.api.models.brand.BrandScreenshotResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandScreenshotResponse response = client.brand().screenshot();\n }\n}', - }, - python: { - method: 'brand.screenshot', - example: - 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.screenshot()\nprint(response.code)', - }, - ruby: { - method: 'brand.screenshot', - example: - 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.screenshot\n\nputs(response)', - }, - typescript: { - method: 'client.brand.screenshot', - example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.screenshot();\n\nconsole.log(response.code);", - }, - }, - }, { name: 'ai_products', endpoint: '/brand/ai/products', diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts index 909c9f5f..787ca94f 100644 --- a/packages/mcp-server/src/methods.ts +++ b/packages/mcp-server/src/methods.ts @@ -88,12 +88,6 @@ export const sdkMethods: SdkMethod[] = [ httpMethod: 'get', httpPath: '/brand/retrieve-simplified', }, - { - clientCallName: 'client.brand.screenshot', - fullyQualifiedName: 'brand.screenshot', - httpMethod: 'get', - httpPath: '/brand/screenshot', - }, { clientCallName: 'client.brand.styleguide', fullyQualifiedName: 'brand.styleguide', diff --git a/src/client.ts b/src/client.ts index 1ba255fb..43c4c913 100644 --- a/src/client.ts +++ b/src/client.ts @@ -45,8 +45,6 @@ import { BrandRetrieveResponse, BrandRetrieveSimplifiedParams, BrandRetrieveSimplifiedResponse, - BrandScreenshotParams, - BrandScreenshotResponse, BrandStyleguideParams, BrandStyleguideResponse, BrandWebScrapeHTMLParams, @@ -781,7 +779,6 @@ export declare namespace BrandDev { type BrandRetrieveByTickerResponse as BrandRetrieveByTickerResponse, type BrandRetrieveNaicsResponse as BrandRetrieveNaicsResponse, type BrandRetrieveSimplifiedResponse as BrandRetrieveSimplifiedResponse, - type BrandScreenshotResponse as BrandScreenshotResponse, type BrandStyleguideResponse as BrandStyleguideResponse, type BrandWebScrapeHTMLResponse as BrandWebScrapeHTMLResponse, type BrandWebScrapeImagesResponse as BrandWebScrapeImagesResponse, @@ -800,7 +797,6 @@ export declare namespace BrandDev { type BrandRetrieveByTickerParams as BrandRetrieveByTickerParams, type BrandRetrieveNaicsParams as BrandRetrieveNaicsParams, type BrandRetrieveSimplifiedParams as BrandRetrieveSimplifiedParams, - type BrandScreenshotParams as BrandScreenshotParams, type BrandStyleguideParams as BrandStyleguideParams, type BrandWebScrapeHTMLParams as BrandWebScrapeHTMLParams, type BrandWebScrapeImagesParams as BrandWebScrapeImagesParams, diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 4a1c0bab..280057f6 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -145,20 +145,6 @@ export class Brand extends APIResource { return this._client.get('/brand/retrieve-simplified', { query, ...options }); } - /** - * Capture a screenshot of a website. Supports both viewport (standard browser - * view) and full-page screenshots. Can also screenshot specific page types (login, - * pricing, etc.) by using heuristics to find the appropriate URL. Either 'domain' - * or 'directUrl' must be provided as a query parameter, but not both. Returns a - * URL to the uploaded screenshot image hosted on our CDN. - */ - screenshot( - query: BrandScreenshotParams | null | undefined = {}, - options?: RequestOptions, - ): APIPromise { - return this._client.get('/brand/screenshot', { query, ...options }); - } - /** * Automatically extract comprehensive design system information from a brand's * website including colors, typography, spacing, shadows, and UI components. @@ -5208,33 +5194,6 @@ export namespace BrandRetrieveSimplifiedResponse { } } -export interface BrandScreenshotResponse { - /** - * HTTP status code - */ - code?: number; - - /** - * The normalized domain that was processed - */ - domain?: string; - - /** - * Public URL of the uploaded screenshot image - */ - screenshot?: string; - - /** - * Type of screenshot that was captured - */ - screenshotType?: 'viewport' | 'fullPage'; - - /** - * Status of the response, e.g., 'ok' - */ - status?: string; -} - export interface BrandStyleguideResponse { /** * HTTP status code @@ -7580,44 +7539,6 @@ export interface BrandRetrieveSimplifiedParams { timeoutMS?: number; } -export interface BrandScreenshotParams { - /** - * A specific URL to screenshot directly, bypassing domain resolution (e.g., - * 'https://example.com/pricing'). When provided, the screenshot is taken of this - * exact URL. - */ - directUrl?: string; - - /** - * Domain name to take screenshot of (e.g., 'example.com', 'google.com'). The - * domain will be automatically normalized and validated. - */ - domain?: string; - - /** - * Optional parameter to determine screenshot type. If 'true', takes a full page - * screenshot capturing all content. If 'false' or not provided, takes a viewport - * screenshot (standard browser view). - */ - fullScreenshot?: 'true' | 'false'; - - /** - * Optional parameter to specify which page type to screenshot. If provided, the - * system will scrape the domain's links and use heuristics to find the most - * appropriate URL for the specified page type (30 supported languages). If not - * provided, screenshots the main domain landing page. Only applicable when using - * 'domain', not 'directUrl'. - */ - page?: 'login' | 'signup' | 'blog' | 'careers' | 'pricing' | 'terms' | 'privacy' | 'contact'; - - /** - * Optional parameter to prioritize screenshot capture. If 'speed', optimizes for - * faster capture with basic quality. If 'quality', optimizes for higher quality - * with longer wait times. Defaults to 'quality' if not provided. - */ - prioritize?: 'speed' | 'quality'; -} - export interface BrandStyleguideParams { /** * A specific URL to fetch the styleguide from directly, bypassing domain @@ -7724,7 +7645,6 @@ export declare namespace Brand { type BrandRetrieveByTickerResponse as BrandRetrieveByTickerResponse, type BrandRetrieveNaicsResponse as BrandRetrieveNaicsResponse, type BrandRetrieveSimplifiedResponse as BrandRetrieveSimplifiedResponse, - type BrandScreenshotResponse as BrandScreenshotResponse, type BrandStyleguideResponse as BrandStyleguideResponse, type BrandWebScrapeHTMLResponse as BrandWebScrapeHTMLResponse, type BrandWebScrapeImagesResponse as BrandWebScrapeImagesResponse, @@ -7743,7 +7663,6 @@ export declare namespace Brand { type BrandRetrieveByTickerParams as BrandRetrieveByTickerParams, type BrandRetrieveNaicsParams as BrandRetrieveNaicsParams, type BrandRetrieveSimplifiedParams as BrandRetrieveSimplifiedParams, - type BrandScreenshotParams as BrandScreenshotParams, type BrandStyleguideParams as BrandStyleguideParams, type BrandWebScrapeHTMLParams as BrandWebScrapeHTMLParams, type BrandWebScrapeImagesParams as BrandWebScrapeImagesParams, diff --git a/src/resources/index.ts b/src/resources/index.ts index 798b703a..6a3a086b 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -15,7 +15,6 @@ export { type BrandRetrieveByTickerResponse, type BrandRetrieveNaicsResponse, type BrandRetrieveSimplifiedResponse, - type BrandScreenshotResponse, type BrandStyleguideResponse, type BrandWebScrapeHTMLResponse, type BrandWebScrapeImagesResponse, @@ -34,7 +33,6 @@ export { type BrandRetrieveByTickerParams, type BrandRetrieveNaicsParams, type BrandRetrieveSimplifiedParams, - type BrandScreenshotParams, type BrandStyleguideParams, type BrandWebScrapeHTMLParams, type BrandWebScrapeImagesParams, diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 3f7c2d22..ad389695 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -309,35 +309,6 @@ describe('resource brand', () => { const response = await client.brand.retrieveSimplified({ domain: 'domain', timeoutMS: 1000 }); }); - // Mock server tests are disabled - test.skip('screenshot', async () => { - const responsePromise = client.brand.screenshot(); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); - - // Mock server tests are disabled - test.skip('screenshot: request options and params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.brand.screenshot( - { - directUrl: 'https://example.com', - domain: 'domain', - fullScreenshot: 'true', - page: 'login', - prioritize: 'speed', - }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(BrandDev.NotFoundError); - }); - // Mock server tests are disabled test.skip('styleguide', async () => { const responsePromise = client.brand.styleguide(); From f774c883e3a05276669b94690517703447ddff9a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:10:45 +0000 Subject: [PATCH 024/100] feat(api): api update --- .stats.yml | 6 +- api.md | 2 - packages/mcp-server/src/code-tool-worker.ts | 1 - packages/mcp-server/src/local-docs-search.ts | 41 -- packages/mcp-server/src/methods.ts | 6 - src/client.ts | 4 - src/resources/brand.ts | 549 ------------------- src/resources/index.ts | 2 - tests/api-resources/brand.test.ts | 27 - 9 files changed, 3 insertions(+), 635 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0198e387..957b33f1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 18 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-73b75de3d3aae732e496f3828fc2c88711969e8abaae060d939da505f36cb3f8.yml -openapi_spec_hash: 30b5dacd44ef41592ba645033b3a1ca3 +configured_endpoints: 17 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-db86584e77523e133c60fce82fe9c3a4957efc0ad317fd0aed1b928c7f0b2f8a.yml +openapi_spec_hash: dfc39b2ad61ed889019ffe6fcb52bcce config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/api.md b/api.md index 9cc9196c..89c0e1eb 100644 --- a/api.md +++ b/api.md @@ -15,7 +15,6 @@ Types: - BrandRetrieveByTickerResponse - BrandRetrieveNaicsResponse - BrandRetrieveSimplifiedResponse -- BrandStyleguideResponse - BrandWebScrapeHTMLResponse - BrandWebScrapeImagesResponse - BrandWebScrapeMdResponse @@ -36,7 +35,6 @@ Methods: - client.brand.retrieveByTicker({ ...params }) -> BrandRetrieveByTickerResponse - client.brand.retrieveNaics({ ...params }) -> BrandRetrieveNaicsResponse - client.brand.retrieveSimplified({ ...params }) -> BrandRetrieveSimplifiedResponse -- client.brand.styleguide({ ...params }) -> BrandStyleguideResponse - client.brand.webScrapeHTML({ ...params }) -> BrandWebScrapeHTMLResponse - client.brand.webScrapeImages({ ...params }) -> BrandWebScrapeImagesResponse - client.brand.webScrapeMd({ ...params }) -> BrandWebScrapeMdResponse diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts index ffcb5e7f..ac12f704 100644 --- a/packages/mcp-server/src/code-tool-worker.ts +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -121,7 +121,6 @@ const fuse = new Fuse( 'client.brand.retrieveByTicker', 'client.brand.retrieveNaics', 'client.brand.retrieveSimplified', - 'client.brand.styleguide', 'client.brand.webScrapeHTML', 'client.brand.webScrapeImages', 'client.brand.webScrapeMd', diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 5844e469..e0c2c1af 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -524,47 +524,6 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, }, }, - { - name: 'styleguide', - endpoint: '/brand/styleguide', - httpMethod: 'get', - summary: 'Extract design system and styleguide from website', - description: - "Automatically extract comprehensive design system information from a brand's website including colors, typography, spacing, shadows, and UI components. Either 'domain' or 'directUrl' must be provided as a query parameter, but not both.", - stainlessPath: '(resource) brand > (method) styleguide', - qualified: 'client.brand.styleguide', - params: ['directUrl?: string;', 'domain?: string;', 'timeoutMS?: number;'], - response: - "{ code?: number; domain?: string; status?: string; styleguide?: { colors: { accent: string; background: string; text: string; }; components: { button: object; card?: object; }; elementSpacing: { lg: string; md: string; sm: string; xl: string; xs: string; }; fontLinks: object; mode: 'light' | 'dark'; shadows: { inner: string; lg: string; md: string; sm: string; xl: string; }; typography: { headings: object; p?: object; }; }; }", - markdown: - "## styleguide\n\n`client.brand.styleguide(directUrl?: string, domain?: string, timeoutMS?: number): { code?: number; domain?: string; status?: string; styleguide?: object; }`\n\n**get** `/brand/styleguide`\n\nAutomatically extract comprehensive design system information from a brand's website including colors, typography, spacing, shadows, and UI components. Either 'domain' or 'directUrl' must be provided as a query parameter, but not both.\n\n### Parameters\n\n- `directUrl?: string`\n A specific URL to fetch the styleguide from directly, bypassing domain resolution (e.g., 'https://example.com/design-system').\n\n- `domain?: string`\n Domain name to extract styleguide from (e.g., 'example.com', 'google.com'). The domain will be automatically normalized and validated.\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- `{ code?: number; domain?: string; status?: string; styleguide?: { colors: { accent: string; background: string; text: string; }; components: { button: object; card?: object; }; elementSpacing: { lg: string; md: string; sm: string; xl: string; xs: string; }; fontLinks: object; mode: 'light' | 'dark'; shadows: { inner: string; lg: string; md: string; sm: string; xl: string; }; typography: { headings: object; p?: object; }; }; }`\n\n - `code?: number`\n - `domain?: string`\n - `status?: string`\n - `styleguide?: { colors: { accent: string; background: string; text: string; }; components: { button: { link?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; color: string; css: string; fontSize: string; fontWeight: number; minHeight: string; minWidth: string; padding: string; textDecoration: string; fontFallbacks?: string[]; fontFamily?: string; textDecorationColor?: string; }; primary?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; color: string; css: string; fontSize: string; fontWeight: number; minHeight: string; minWidth: string; padding: string; textDecoration: string; fontFallbacks?: string[]; fontFamily?: string; textDecorationColor?: string; }; secondary?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; color: string; css: string; fontSize: string; fontWeight: number; minHeight: string; minWidth: string; padding: string; textDecoration: string; fontFallbacks?: string[]; fontFamily?: string; textDecorationColor?: string; }; }; card?: { backgroundColor: string; borderColor: string; borderRadius: string; borderStyle: string; borderWidth: string; boxShadow: string; css: string; padding: string; textColor: string; }; }; elementSpacing: { lg: string; md: string; sm: string; xl: string; xs: string; }; fontLinks: object; mode: 'light' | 'dark'; shadows: { inner: string; lg: string; md: string; sm: string; xl: string; }; typography: { headings: { h1?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; h2?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; h3?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; h4?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; }; p?: { fontFallbacks: string[]; fontFamily: string; fontSize: string; fontWeight: number; letterSpacing: string; lineHeight: string; }; }; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.styleguide();\n\nconsole.log(response);\n```", - perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/styleguide \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().styleguide', - example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandStyleguideParams;\nimport com.branddev.api.models.brand.BrandStyleguideResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandStyleguideResponse response = client.brand().styleguide();\n }\n}', - }, - python: { - method: 'brand.styleguide', - example: - 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.styleguide()\nprint(response.styleguide)', - }, - ruby: { - method: 'brand.styleguide', - example: - 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.styleguide\n\nputs(response)', - }, - typescript: { - method: 'client.brand.styleguide', - example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.styleguide();\n\nconsole.log(response.styleguide);", - }, - }, - }, { name: 'ai_products', endpoint: '/brand/ai/products', diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts index 787ca94f..42cd024a 100644 --- a/packages/mcp-server/src/methods.ts +++ b/packages/mcp-server/src/methods.ts @@ -88,12 +88,6 @@ export const sdkMethods: SdkMethod[] = [ httpMethod: 'get', httpPath: '/brand/retrieve-simplified', }, - { - clientCallName: 'client.brand.styleguide', - fullyQualifiedName: 'brand.styleguide', - httpMethod: 'get', - httpPath: '/brand/styleguide', - }, { clientCallName: 'client.brand.webScrapeHTML', fullyQualifiedName: 'brand.webScrapeHTML', diff --git a/src/client.ts b/src/client.ts index 43c4c913..2ca9053c 100644 --- a/src/client.ts +++ b/src/client.ts @@ -45,8 +45,6 @@ import { BrandRetrieveResponse, BrandRetrieveSimplifiedParams, BrandRetrieveSimplifiedResponse, - BrandStyleguideParams, - BrandStyleguideResponse, BrandWebScrapeHTMLParams, BrandWebScrapeHTMLResponse, BrandWebScrapeImagesParams, @@ -779,7 +777,6 @@ export declare namespace BrandDev { type BrandRetrieveByTickerResponse as BrandRetrieveByTickerResponse, type BrandRetrieveNaicsResponse as BrandRetrieveNaicsResponse, type BrandRetrieveSimplifiedResponse as BrandRetrieveSimplifiedResponse, - type BrandStyleguideResponse as BrandStyleguideResponse, type BrandWebScrapeHTMLResponse as BrandWebScrapeHTMLResponse, type BrandWebScrapeImagesResponse as BrandWebScrapeImagesResponse, type BrandWebScrapeMdResponse as BrandWebScrapeMdResponse, @@ -797,7 +794,6 @@ export declare namespace BrandDev { type BrandRetrieveByTickerParams as BrandRetrieveByTickerParams, type BrandRetrieveNaicsParams as BrandRetrieveNaicsParams, type BrandRetrieveSimplifiedParams as BrandRetrieveSimplifiedParams, - type BrandStyleguideParams as BrandStyleguideParams, type BrandWebScrapeHTMLParams as BrandWebScrapeHTMLParams, type BrandWebScrapeImagesParams as BrandWebScrapeImagesParams, type BrandWebScrapeMdParams as BrandWebScrapeMdParams, diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 280057f6..56231af8 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -145,19 +145,6 @@ export class Brand extends APIResource { return this._client.get('/brand/retrieve-simplified', { query, ...options }); } - /** - * Automatically extract comprehensive design system information from a brand's - * website including colors, typography, spacing, shadows, and UI components. - * Either 'domain' or 'directUrl' must be provided as a query parameter, but not - * both. - */ - styleguide( - query: BrandStyleguideParams | null | undefined = {}, - options?: RequestOptions, - ): APIPromise { - return this._client.get('/brand/styleguide', { query, ...options }); - } - /** * Scrapes the given URL and returns the raw HTML content of the page. */ @@ -5194,519 +5181,6 @@ export namespace BrandRetrieveSimplifiedResponse { } } -export interface BrandStyleguideResponse { - /** - * HTTP status code - */ - code?: number; - - /** - * The normalized domain that was processed - */ - domain?: string; - - /** - * Status of the response, e.g., 'ok' - */ - status?: string; - - /** - * Comprehensive styleguide data extracted from the website - */ - styleguide?: BrandStyleguideResponse.Styleguide; -} - -export namespace BrandStyleguideResponse { - /** - * Comprehensive styleguide data extracted from the website - */ - export interface Styleguide { - /** - * Primary colors used on the website - */ - colors: Styleguide.Colors; - - /** - * UI component styles - */ - components: Styleguide.Components; - - /** - * Spacing system used on the website - */ - elementSpacing: Styleguide.ElementSpacing; - - /** - * Font assets keyed by family name as it appears in fontFamily/fontFallbacks - * (non-generic names only). Clients match typography.fontFamily / fontWeight or - * button styles to pick a file URL from files. - */ - fontLinks: { [key: string]: Styleguide.FontLinks }; - - /** - * The primary color mode of the website design - */ - mode: 'light' | 'dark'; - - /** - * Shadow styles used on the website - */ - shadows: Styleguide.Shadows; - - /** - * Typography styles used on the website - */ - typography: Styleguide.Typography; - } - - export namespace Styleguide { - /** - * Primary colors used on the website - */ - export interface Colors { - /** - * Accent color (hex format) - */ - accent: string; - - /** - * Background color (hex format) - */ - background: string; - - /** - * Text color (hex format) - */ - text: string; - } - - /** - * UI component styles - */ - export interface Components { - /** - * Button component styles - */ - button: Components.Button; - - /** - * Card component style - */ - card?: Components.Card; - } - - export namespace Components { - /** - * Button component styles - */ - export interface Button { - link?: Button.Link; - - primary?: Button.Primary; - - secondary?: Button.Secondary; - } - - export namespace Button { - export interface Link { - backgroundColor: string; - - /** - * Border color as CSS hex (#RRGGBB or #RRGGBBAA when computed border-color has - * alpha) - */ - borderColor: string; - - borderRadius: string; - - borderStyle: string; - - borderWidth: string; - - /** - * Computed box-shadow (comma-separated layers when present) - */ - boxShadow: string; - - color: string; - - /** - * Ready-to-use CSS declaration block for this component style - */ - css: string; - - fontSize: string; - - fontWeight: number; - - /** - * Sampled minimum height of the button box (typically px) - */ - minHeight: string; - - /** - * Sampled minimum width of the button box (typically px) - */ - minWidth: string; - - padding: string; - - textDecoration: string; - - /** - * Full ordered font list from computed font-family - */ - fontFallbacks?: Array; - - /** - * Primary button typeface (first in fontFallbacks) - */ - fontFamily?: string; - - /** - * Hex color of the underline when it differs from the text color - */ - textDecorationColor?: string; - } - - export interface Primary { - backgroundColor: string; - - /** - * Border color as CSS hex (#RRGGBB or #RRGGBBAA when computed border-color has - * alpha) - */ - borderColor: string; - - borderRadius: string; - - borderStyle: string; - - borderWidth: string; - - /** - * Computed box-shadow (comma-separated layers when present) - */ - boxShadow: string; - - color: string; - - /** - * Ready-to-use CSS declaration block for this component style - */ - css: string; - - fontSize: string; - - fontWeight: number; - - /** - * Sampled minimum height of the button box (typically px) - */ - minHeight: string; - - /** - * Sampled minimum width of the button box (typically px) - */ - minWidth: string; - - padding: string; - - textDecoration: string; - - /** - * Full ordered font list from computed font-family - */ - fontFallbacks?: Array; - - /** - * Primary button typeface (first in fontFallbacks) - */ - fontFamily?: string; - - /** - * Hex color of the underline when it differs from the text color - */ - textDecorationColor?: string; - } - - export interface Secondary { - backgroundColor: string; - - /** - * Border color as CSS hex (#RRGGBB or #RRGGBBAA when computed border-color has - * alpha) - */ - borderColor: string; - - borderRadius: string; - - borderStyle: string; - - borderWidth: string; - - /** - * Computed box-shadow (comma-separated layers when present) - */ - boxShadow: string; - - color: string; - - /** - * Ready-to-use CSS declaration block for this component style - */ - css: string; - - fontSize: string; - - fontWeight: number; - - /** - * Sampled minimum height of the button box (typically px) - */ - minHeight: string; - - /** - * Sampled minimum width of the button box (typically px) - */ - minWidth: string; - - padding: string; - - textDecoration: string; - - /** - * Full ordered font list from computed font-family - */ - fontFallbacks?: Array; - - /** - * Primary button typeface (first in fontFallbacks) - */ - fontFamily?: string; - - /** - * Hex color of the underline when it differs from the text color - */ - textDecorationColor?: string; - } - } - - /** - * Card component style - */ - export interface Card { - backgroundColor: string; - - /** - * Border color as CSS hex (#RRGGBB or #RRGGBBAA when computed border-color has - * alpha) - */ - borderColor: string; - - borderRadius: string; - - borderStyle: string; - - borderWidth: string; - - boxShadow: string; - - /** - * Ready-to-use CSS declaration block for this component style - */ - css: string; - - padding: string; - - textColor: string; - } - } - - /** - * Spacing system used on the website - */ - export interface ElementSpacing { - lg: string; - - md: string; - - sm: string; - - xl: string; - - xs: string; - } - - export interface FontLinks { - /** - * Upright font files keyed by weight string (e.g. "400" for regular, "500", - * "700"). Values are absolute URLs. - */ - files: { [key: string]: string }; - - type: 'google' | 'custom'; - - /** - * Google Fonts category when type is google (e.g. sans-serif, serif, monospace, - * display, handwriting). Omitted for custom fonts when unknown. - */ - category?: string; - - /** - * Present when type is custom: human-readable name derived from the fontLinks key - * (strip build/hash suffixes, split camelCase / PascalCase, normalize separators). - * Google entries omit this. - */ - displayName?: string; - } - - /** - * Shadow styles used on the website - */ - export interface Shadows { - inner: string; - - lg: string; - - md: string; - - sm: string; - - xl: string; - } - - /** - * Typography styles used on the website - */ - export interface Typography { - /** - * Heading styles - */ - headings: Typography.Headings; - - p?: Typography.P; - } - - export namespace Typography { - /** - * Heading styles - */ - export interface Headings { - h1?: Headings.H1; - - h2?: Headings.H2; - - h3?: Headings.H3; - - h4?: Headings.H4; - } - - export namespace Headings { - export interface H1 { - /** - * Full ordered font list from resolved computed font-family - */ - fontFallbacks: Array; - - /** - * Primary face (first family in the computed stack) - */ - fontFamily: string; - - fontSize: string; - - fontWeight: number; - - letterSpacing: string; - - lineHeight: string; - } - - export interface H2 { - /** - * Full ordered font list from resolved computed font-family - */ - fontFallbacks: Array; - - /** - * Primary face (first family in the computed stack) - */ - fontFamily: string; - - fontSize: string; - - fontWeight: number; - - letterSpacing: string; - - lineHeight: string; - } - - export interface H3 { - /** - * Full ordered font list from resolved computed font-family - */ - fontFallbacks: Array; - - /** - * Primary face (first family in the computed stack) - */ - fontFamily: string; - - fontSize: string; - - fontWeight: number; - - letterSpacing: string; - - lineHeight: string; - } - - export interface H4 { - /** - * Full ordered font list from resolved computed font-family - */ - fontFallbacks: Array; - - /** - * Primary face (first family in the computed stack) - */ - fontFamily: string; - - fontSize: string; - - fontWeight: number; - - letterSpacing: string; - - lineHeight: string; - } - } - - export interface P { - /** - * Full ordered font list from resolved computed font-family - */ - fontFallbacks: Array; - - /** - * Primary face (first family in the computed stack) - */ - fontFamily: string; - - fontSize: string; - - fontWeight: number; - - letterSpacing: string; - - lineHeight: string; - } - } - } -} - export interface BrandWebScrapeHTMLResponse { /** * Raw HTML content of the page @@ -7539,27 +7013,6 @@ export interface BrandRetrieveSimplifiedParams { timeoutMS?: number; } -export interface BrandStyleguideParams { - /** - * A specific URL to fetch the styleguide from directly, bypassing domain - * resolution (e.g., 'https://example.com/design-system'). - */ - directUrl?: string; - - /** - * Domain name to extract styleguide from (e.g., 'example.com', 'google.com'). The - * domain will be automatically normalized and validated. - */ - domain?: string; - - /** - * 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). - */ - timeoutMS?: number; -} - export interface BrandWebScrapeHTMLParams { /** * Full URL to scrape (must include http:// or https:// protocol) @@ -7645,7 +7098,6 @@ export declare namespace Brand { type BrandRetrieveByTickerResponse as BrandRetrieveByTickerResponse, type BrandRetrieveNaicsResponse as BrandRetrieveNaicsResponse, type BrandRetrieveSimplifiedResponse as BrandRetrieveSimplifiedResponse, - type BrandStyleguideResponse as BrandStyleguideResponse, type BrandWebScrapeHTMLResponse as BrandWebScrapeHTMLResponse, type BrandWebScrapeImagesResponse as BrandWebScrapeImagesResponse, type BrandWebScrapeMdResponse as BrandWebScrapeMdResponse, @@ -7663,7 +7115,6 @@ export declare namespace Brand { type BrandRetrieveByTickerParams as BrandRetrieveByTickerParams, type BrandRetrieveNaicsParams as BrandRetrieveNaicsParams, type BrandRetrieveSimplifiedParams as BrandRetrieveSimplifiedParams, - type BrandStyleguideParams as BrandStyleguideParams, type BrandWebScrapeHTMLParams as BrandWebScrapeHTMLParams, type BrandWebScrapeImagesParams as BrandWebScrapeImagesParams, type BrandWebScrapeMdParams as BrandWebScrapeMdParams, diff --git a/src/resources/index.ts b/src/resources/index.ts index 6a3a086b..97308d9c 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -15,7 +15,6 @@ export { type BrandRetrieveByTickerResponse, type BrandRetrieveNaicsResponse, type BrandRetrieveSimplifiedResponse, - type BrandStyleguideResponse, type BrandWebScrapeHTMLResponse, type BrandWebScrapeImagesResponse, type BrandWebScrapeMdResponse, @@ -33,7 +32,6 @@ export { type BrandRetrieveByTickerParams, type BrandRetrieveNaicsParams, type BrandRetrieveSimplifiedParams, - type BrandStyleguideParams, type BrandWebScrapeHTMLParams, type BrandWebScrapeImagesParams, type BrandWebScrapeMdParams, diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index ad389695..cefbdbf8 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -309,33 +309,6 @@ describe('resource brand', () => { const response = await client.brand.retrieveSimplified({ domain: 'domain', timeoutMS: 1000 }); }); - // Mock server tests are disabled - test.skip('styleguide', async () => { - const responsePromise = client.brand.styleguide(); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); - - // Mock server tests are disabled - test.skip('styleguide: request options and params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.brand.styleguide( - { - directUrl: 'https://example.com', - domain: 'domain', - timeoutMS: 1000, - }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(BrandDev.NotFoundError); - }); - // Mock server tests are disabled test.skip('webScrapeHTML: only required params', async () => { const responsePromise = client.brand.webScrapeHTML({ url: 'https://example.com' }); From 96f634afd283dfdb24186d77fd89e6d7db7654e1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:45:37 +0000 Subject: [PATCH 025/100] feat(api): api update --- .stats.yml | 4 +-- packages/mcp-server/src/local-docs-search.ts | 28 +++++++++----------- src/resources/brand.ts | 25 +++++++---------- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/.stats.yml b/.stats.yml index 957b33f1..d1e595cf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-db86584e77523e133c60fce82fe9c3a4957efc0ad317fd0aed1b928c7f0b2f8a.yml -openapi_spec_hash: dfc39b2ad61ed889019ffe6fcb52bcce +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-d2e5adb24c5fcf4801996dc77d972711ae67b658a8d2a0ea8e18bb0856489b90.yml +openapi_spec_hash: 3796c471b7905708bfc8ea905abff5a5 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index e0c2c1af..edbde185 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -95,8 +95,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ endpoint: '/brand/retrieve-by-ticker', httpMethod: 'get', summary: 'Retrieve brand data by stock ticker', - description: - 'Retrieve brand information using a stock ticker symbol. This endpoint looks up the company associated with the ticker and returns its brand data.', + description: 'Retrieve brand information using a stock ticker symbol.', stainlessPath: '(resource) brand > (method) retrieve_by_ticker', qualified: 'client.brand.retrieveByTicker', params: [ @@ -109,7 +108,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_ticker\n\n`client.brand.retrieveByTicker(ticker: string, force_language?: string, maxSpeed?: boolean, ticker_exchange?: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-ticker`\n\nRetrieve brand information using a stock ticker symbol. This endpoint looks up the company associated with the ticker and returns its brand data.\n\n### Parameters\n\n- `ticker: string`\n Stock ticker symbol to retrieve brand data for (e.g., 'AAPL', 'GOOGL', 'BRK.A'). Must be 1-15 characters, letters/numbers/dots only.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `ticker_exchange?: string`\n Optional stock exchange for the ticker. Defaults to NASDAQ if not specified.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response);\n```", + "## retrieve_by_ticker\n\n`client.brand.retrieveByTicker(ticker: string, force_language?: string, maxSpeed?: boolean, ticker_exchange?: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-ticker`\n\nRetrieve brand information using a stock ticker symbol.\n\n### Parameters\n\n- `ticker: string`\n Stock ticker symbol to retrieve brand data for (e.g., 'AAPL', 'GOOGL', 'BRK.A'). Must be 1-15 characters, letters/numbers/dots only.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `ticker_exchange?: string`\n Optional stock exchange for the ticker. Defaults to NASDAQ if not specified.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -143,14 +142,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'get', summary: 'Retrieve brand data by ISIN', description: - 'Retrieve brand information using an ISIN (International Securities Identification Number). This endpoint looks up the company associated with the ISIN and returns its brand data.', + 'Retrieve brand information using an ISIN (International Securities Identification Number). ', stainlessPath: '(resource) brand > (method) retrieve_by_isin', qualified: 'client.brand.retrieveByIsin', params: ['isin: string;', 'force_language?: string;', 'maxSpeed?: boolean;', 'timeoutMS?: number;'], response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_isin\n\n`client.brand.retrieveByIsin(isin: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-isin`\n\nRetrieve brand information using an ISIN (International Securities Identification Number). This endpoint looks up the company associated with the ISIN and returns its brand data.\n\n### Parameters\n\n- `isin: string`\n ISIN (International Securities Identification Number) to retrieve brand data for (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters followed by 9 alphanumeric characters and ending with a digit.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response);\n```", + "## retrieve_by_isin\n\n`client.brand.retrieveByIsin(isin: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-isin`\n\nRetrieve brand information using an ISIN (International Securities Identification Number). \n\n### Parameters\n\n- `isin: string`\n ISIN (International Securities Identification Number) to retrieve brand data for (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters followed by 9 alphanumeric characters and ending with a digit.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -183,8 +182,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ endpoint: '/brand/retrieve-by-name', httpMethod: 'get', summary: 'Retrieve brand data by company name', - description: - 'Retrieve brand information using a company name. This endpoint searches for the company by name and returns its brand data.', + description: 'Retrieve brand information using a company name.', stainlessPath: '(resource) brand > (method) retrieve_by_name', qualified: 'client.brand.retrieveByName', params: [ @@ -197,7 +195,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_name\n\n`client.brand.retrieveByName(name: string, country_gl?: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-name`\n\nRetrieve brand information using a company name. This endpoint searches for the company by name and returns its brand data.\n\n### Parameters\n\n- `name: string`\n Company name to retrieve brand data for (e.g., 'Apple Inc', 'Microsoft Corporation'). Must be 3-30 characters.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response);\n```", + "## retrieve_by_name\n\n`client.brand.retrieveByName(name: string, country_gl?: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-name`\n\nRetrieve brand information using a company name.\n\n### Parameters\n\n- `name: string`\n Company name to retrieve brand data for (e.g., 'Apple Inc', 'Microsoft Corporation'). Must be 3-30 characters.\n\n- `country_gl?: string`\n Optional country code hint (GL parameter) to specify the country for the company name.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -231,14 +229,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'get', summary: 'Retrieve brand data by email address', description: - 'Retrieve brand information using an email address while detecting disposable and free email addresses. This endpoint extracts the domain from the email address and returns brand data for that domain. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.', + 'Retrieve brand information using an email address while detecting disposable and free email addresses. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.', stainlessPath: '(resource) brand > (method) retrieve_by_email', qualified: 'client.brand.retrieveByEmail', params: ['email: string;', 'force_language?: string;', 'maxSpeed?: boolean;', 'timeoutMS?: number;'], response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_email\n\n`client.brand.retrieveByEmail(email: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-email`\n\nRetrieve brand information using an email address while detecting disposable and free email addresses. This endpoint extracts the domain from the email address and returns brand data for that domain. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.\n\n### Parameters\n\n- `email: string`\n Email address to retrieve brand data for (e.g., 'contact@example.com'). The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", + "## retrieve_by_email\n\n`client.brand.retrieveByEmail(email: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-email`\n\nRetrieve brand information using an email address while detecting disposable and free email addresses. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.\n\n### Parameters\n\n- `email: string`\n Email address to retrieve brand data for (e.g., 'contact@example.com'). The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -289,7 +287,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## identify_from_transaction\n\n`client.brand.identifyFromTransaction(transaction_info: string, city?: string, country_gl?: string, force_language?: string, high_confidence_only?: boolean, maxSpeed?: boolean, mcc?: string, phone?: number, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/transaction_identifier`\n\nEndpoint specially designed for platforms that want to identify transaction data by the transaction title.\n\n### Parameters\n\n- `transaction_info: string`\n Transaction information to identify the brand\n\n- `city?: string`\n Optional city name to prioritize when searching for the brand.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `high_confidence_only?: boolean`\n When set to true, the API will perform an additional verification steps to ensure the identified brand matches the transaction with high confidence. Defaults to false.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `mcc?: string`\n Optional Merchant Category Code (MCC) to help identify the business category/industry. \n\n- `phone?: number`\n Optional phone number from the transaction to help verify brand match.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.identifyFromTransaction({ transaction_info: 'transaction_info' });\n\nconsole.log(response);\n```", + "## identify_from_transaction\n\n`client.brand.identifyFromTransaction(transaction_info: string, city?: string, country_gl?: string, force_language?: string, high_confidence_only?: boolean, maxSpeed?: boolean, mcc?: string, phone?: number, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/transaction_identifier`\n\nEndpoint specially designed for platforms that want to identify transaction data by the transaction title.\n\n### Parameters\n\n- `transaction_info: string`\n Transaction information to identify the brand\n\n- `city?: string`\n Optional city name to prioritize when searching for the brand.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `high_confidence_only?: boolean`\n When set to true, the API will perform an additional verification steps to ensure the identified brand matches the transaction with high confidence.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `mcc?: string`\n Optional Merchant Category Code (MCC) to help identify the business category/industry. \n\n- `phone?: number`\n Optional phone number from the transaction to help verify brand match.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.identifyFromTransaction({ transaction_info: 'transaction_info' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -489,14 +487,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'get', summary: 'Retrieve simplified brand data by domain', description: - 'Returns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. This endpoint is optimized for faster responses and reduced data transfer.', + 'Returns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. Optimized for faster responses and reduced data transfer.', stainlessPath: '(resource) brand > (method) retrieve_simplified', qualified: 'client.brand.retrieveSimplified', params: ['domain: string;', 'timeoutMS?: number;'], response: "{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_simplified\n\n`client.brand.retrieveSimplified(domain: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-simplified`\n\nReturns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. This endpoint is optimized for faster responses and reduced data transfer.\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve simplified brand data for\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- `{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveSimplified({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## retrieve_simplified\n\n`client.brand.retrieveSimplified(domain: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-simplified`\n\nReturns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. Optimized for faster responses and reduced data transfer.\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve simplified brand data for\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- `{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveSimplified({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -737,14 +735,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ endpoint: '/web/scrape/sitemap', httpMethod: 'get', summary: 'Crawl Sitemap', - description: "Crawl an entire website's sitemap and return all discovered page URLs", + description: "Crawl an entire website's sitemap and return all discovered page URLs.", stainlessPath: '(resource) brand > (method) web_scrape_sitemap', qualified: 'client.brand.webScrapeSitemap', params: ['domain: string;', 'maxLinks?: number;'], response: '{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }', markdown: - "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 56231af8..787ab13b 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -78,9 +78,8 @@ export class Brand extends APIResource { /** * Retrieve brand information using an email address while detecting disposable and - * free email addresses. This endpoint extracts the domain from the email address - * and returns brand data for that domain. Disposable and free email addresses - * (like gmail.com, yahoo.com) will throw a 422 error. + * free email addresses. Disposable and free email addresses (like gmail.com, + * yahoo.com) will throw a 422 error. */ retrieveByEmail( query: BrandRetrieveByEmailParams, @@ -91,8 +90,7 @@ export class Brand extends APIResource { /** * Retrieve brand information using an ISIN (International Securities - * Identification Number). This endpoint looks up the company associated with the - * ISIN and returns its brand data. + * Identification Number). */ retrieveByIsin( query: BrandRetrieveByIsinParams, @@ -102,8 +100,7 @@ export class Brand extends APIResource { } /** - * Retrieve brand information using a company name. This endpoint searches for the - * company by name and returns its brand data. + * Retrieve brand information using a company name. */ retrieveByName( query: BrandRetrieveByNameParams, @@ -113,8 +110,7 @@ export class Brand extends APIResource { } /** - * Retrieve brand information using a stock ticker symbol. This endpoint looks up - * the company associated with the ticker and returns its brand data. + * Retrieve brand information using a stock ticker symbol. */ retrieveByTicker( query: BrandRetrieveByTickerParams, @@ -135,8 +131,8 @@ export class Brand extends APIResource { /** * Returns a simplified version of brand data containing only essential - * information: domain, title, colors, logos, and backdrops. This endpoint is - * optimized for faster responses and reduced data transfer. + * information: domain, title, colors, logos, and backdrops. Optimized for faster + * responses and reduced data transfer. */ retrieveSimplified( query: BrandRetrieveSimplifiedParams, @@ -175,7 +171,7 @@ export class Brand extends APIResource { } /** - * Crawl an entire website's sitemap and return all discovered page URLs + * Crawl an entire website's sitemap and return all discovered page URLs. */ webScrapeSitemap( query: BrandWebScrapeSitemapParams, @@ -6000,7 +5996,6 @@ export interface BrandIdentifyFromTransactionParams { /** * When set to true, the API will perform an additional verification steps to * ensure the identified brand matches the transaction with high confidence. - * Defaults to false. */ high_confidence_only?: boolean; @@ -6364,8 +6359,8 @@ export interface BrandRetrieveByNameParams { name: string; /** - * Optional country code (GL parameter) to specify the country. This affects the - * geographic location used for search queries. + * Optional country code hint (GL parameter) to specify the country for the company + * name. */ country_gl?: | 'ad' From 3f941edf853250925cf0b5d314affb2dad20ea8f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:09:20 +0000 Subject: [PATCH 026/100] feat(api): api update --- .stats.yml | 6 +- api.md | 2 - packages/mcp-server/src/code-tool-worker.ts | 1 - packages/mcp-server/src/local-docs-search.ts | 40 ---------- packages/mcp-server/src/methods.ts | 6 -- src/client.ts | 4 - src/resources/brand.ts | 80 -------------------- src/resources/index.ts | 2 - tests/api-resources/brand.test.ts | 22 ------ 9 files changed, 3 insertions(+), 160 deletions(-) diff --git a/.stats.yml b/.stats.yml index d1e595cf..f73f1bc1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 17 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-d2e5adb24c5fcf4801996dc77d972711ae67b658a8d2a0ea8e18bb0856489b90.yml -openapi_spec_hash: 3796c471b7905708bfc8ea905abff5a5 +configured_endpoints: 16 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-071c7e9274f7e2f76732f22559fe8b4b75043a73c2c4af74ad2cc429d4bae357.yml +openapi_spec_hash: e7c47fbf61de6e2e9339f1dbb428cb8e config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/api.md b/api.md index 89c0e1eb..e38e7019 100644 --- a/api.md +++ b/api.md @@ -13,7 +13,6 @@ Types: - BrandRetrieveByIsinResponse - BrandRetrieveByNameResponse - BrandRetrieveByTickerResponse -- BrandRetrieveNaicsResponse - BrandRetrieveSimplifiedResponse - BrandWebScrapeHTMLResponse - BrandWebScrapeImagesResponse @@ -33,7 +32,6 @@ Methods: - client.brand.retrieveByIsin({ ...params }) -> BrandRetrieveByIsinResponse - client.brand.retrieveByName({ ...params }) -> BrandRetrieveByNameResponse - client.brand.retrieveByTicker({ ...params }) -> BrandRetrieveByTickerResponse -- client.brand.retrieveNaics({ ...params }) -> BrandRetrieveNaicsResponse - client.brand.retrieveSimplified({ ...params }) -> BrandRetrieveSimplifiedResponse - client.brand.webScrapeHTML({ ...params }) -> BrandWebScrapeHTMLResponse - client.brand.webScrapeImages({ ...params }) -> BrandWebScrapeImagesResponse diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts index ac12f704..d55e8eb3 100644 --- a/packages/mcp-server/src/code-tool-worker.ts +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -119,7 +119,6 @@ const fuse = new Fuse( 'client.brand.retrieveByIsin', 'client.brand.retrieveByName', 'client.brand.retrieveByTicker', - 'client.brand.retrieveNaics', 'client.brand.retrieveSimplified', 'client.brand.webScrapeHTML', 'client.brand.webScrapeImages', diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index edbde185..e948ca6f 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -315,46 +315,6 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, }, }, - { - name: 'retrieve_naics', - endpoint: '/brand/naics', - httpMethod: 'get', - summary: 'Retrieve NAICS code for any brand', - description: 'Endpoint to classify any brand into a 2022 NAICS code.', - stainlessPath: '(resource) brand > (method) retrieve_naics', - qualified: 'client.brand.retrieveNaics', - params: ['input: string;', 'maxResults?: number;', 'minResults?: number;', 'timeoutMS?: number;'], - response: - "{ codes?: { code: string; confidence: 'high' | 'medium' | 'low'; name: string; }[]; domain?: string; status?: string; type?: string; }", - markdown: - "## retrieve_naics\n\n`client.brand.retrieveNaics(input: string, maxResults?: number, minResults?: number, timeoutMS?: number): { codes?: object[]; domain?: string; status?: string; type?: string; }`\n\n**get** `/brand/naics`\n\nEndpoint to classify any brand into a 2022 NAICS code.\n\n### Parameters\n\n- `input: string`\n Brand domain or title to retrieve NAICS code for. If a valid domain is provided in `input`, it will be used for classification, otherwise, we will search for the brand using the provided title.\n\n- `maxResults?: number`\n Maximum number of NAICS codes to return. Must be between 1 and 10. Defaults to 5.\n\n- `minResults?: number`\n Minimum number of NAICS codes to return. Must be at least 1. Defaults to 1.\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- `{ codes?: { code: string; confidence: 'high' | 'medium' | 'low'; name: string; }[]; domain?: string; status?: string; type?: string; }`\n\n - `codes?: { code: string; confidence: 'high' | 'medium' | 'low'; name: string; }[]`\n - `domain?: string`\n - `status?: string`\n - `type?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveNaics({ input: 'input' });\n\nconsole.log(response);\n```", - perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/naics \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().retrieveNaics', - example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveNaicsParams;\nimport com.branddev.api.models.brand.BrandRetrieveNaicsResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveNaicsParams params = BrandRetrieveNaicsParams.builder()\n .input("input")\n .build();\n BrandRetrieveNaicsResponse response = client.brand().retrieveNaics(params);\n }\n}', - }, - python: { - method: 'brand.retrieve_naics', - example: - 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.retrieve_naics(\n input="input",\n)\nprint(response.codes)', - }, - ruby: { - method: 'brand.retrieve_naics', - example: - 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.retrieve_naics(input: "input")\n\nputs(response)', - }, - typescript: { - method: 'client.brand.retrieveNaics', - example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveNaics({ input: 'input' });\n\nconsole.log(response.codes);", - }, - }, - }, { name: 'ai_query', endpoint: '/brand/ai/query', diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts index 42cd024a..ce712dfb 100644 --- a/packages/mcp-server/src/methods.ts +++ b/packages/mcp-server/src/methods.ts @@ -76,12 +76,6 @@ export const sdkMethods: SdkMethod[] = [ httpMethod: 'get', httpPath: '/brand/retrieve-by-ticker', }, - { - clientCallName: 'client.brand.retrieveNaics', - fullyQualifiedName: 'brand.retrieveNaics', - httpMethod: 'get', - httpPath: '/brand/naics', - }, { clientCallName: 'client.brand.retrieveSimplified', fullyQualifiedName: 'brand.retrieveSimplified', diff --git a/src/client.ts b/src/client.ts index 2ca9053c..9af23453 100644 --- a/src/client.ts +++ b/src/client.ts @@ -39,8 +39,6 @@ import { BrandRetrieveByNameResponse, BrandRetrieveByTickerParams, BrandRetrieveByTickerResponse, - BrandRetrieveNaicsParams, - BrandRetrieveNaicsResponse, BrandRetrieveParams, BrandRetrieveResponse, BrandRetrieveSimplifiedParams, @@ -775,7 +773,6 @@ export declare namespace BrandDev { type BrandRetrieveByIsinResponse as BrandRetrieveByIsinResponse, type BrandRetrieveByNameResponse as BrandRetrieveByNameResponse, type BrandRetrieveByTickerResponse as BrandRetrieveByTickerResponse, - type BrandRetrieveNaicsResponse as BrandRetrieveNaicsResponse, type BrandRetrieveSimplifiedResponse as BrandRetrieveSimplifiedResponse, type BrandWebScrapeHTMLResponse as BrandWebScrapeHTMLResponse, type BrandWebScrapeImagesResponse as BrandWebScrapeImagesResponse, @@ -792,7 +789,6 @@ export declare namespace BrandDev { type BrandRetrieveByIsinParams as BrandRetrieveByIsinParams, type BrandRetrieveByNameParams as BrandRetrieveByNameParams, type BrandRetrieveByTickerParams as BrandRetrieveByTickerParams, - type BrandRetrieveNaicsParams as BrandRetrieveNaicsParams, type BrandRetrieveSimplifiedParams as BrandRetrieveSimplifiedParams, type BrandWebScrapeHTMLParams as BrandWebScrapeHTMLParams, type BrandWebScrapeImagesParams as BrandWebScrapeImagesParams, diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 787ab13b..f061f5c2 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -119,16 +119,6 @@ export class Brand extends APIResource { return this._client.get('/brand/retrieve-by-ticker', { query, ...options }); } - /** - * Endpoint to classify any brand into a 2022 NAICS code. - */ - retrieveNaics( - query: BrandRetrieveNaicsParams, - options?: RequestOptions, - ): APIPromise { - return this._client.get('/brand/naics', { query, ...options }); - } - /** * Returns a simplified version of brand data containing only essential * information: domain, title, colors, logos, and backdrops. Optimized for faster @@ -4959,47 +4949,6 @@ export namespace BrandRetrieveByTickerResponse { } } -export interface BrandRetrieveNaicsResponse { - /** - * Array of NAICS codes and titles. - */ - codes?: Array; - - /** - * Domain found for the brand - */ - domain?: string; - - /** - * Status of the response, e.g., 'ok' - */ - status?: string; - - /** - * Industry classification type, for naics api it will be `naics` - */ - type?: string; -} - -export namespace BrandRetrieveNaicsResponse { - export interface Code { - /** - * NAICS code - */ - code: string; - - /** - * Confidence level for how well this NAICS code matches the company description - */ - confidence: 'high' | 'medium' | 'low'; - - /** - * NAICS title - */ - name: string; - } -} - export interface BrandRetrieveSimplifiedResponse { /** * Simplified brand information @@ -6967,33 +6916,6 @@ export interface BrandRetrieveByTickerParams { timeoutMS?: number; } -export interface BrandRetrieveNaicsParams { - /** - * Brand domain or title to retrieve NAICS code for. If a valid domain is provided - * in `input`, it will be used for classification, otherwise, we will search for - * the brand using the provided title. - */ - input: string; - - /** - * Maximum number of NAICS codes to return. Must be between 1 and 10. Defaults - * to 5. - */ - maxResults?: number; - - /** - * Minimum number of NAICS codes to return. Must be at least 1. Defaults to 1. - */ - minResults?: number; - - /** - * 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). - */ - timeoutMS?: number; -} - export interface BrandRetrieveSimplifiedParams { /** * Domain name to retrieve simplified brand data for @@ -7091,7 +7013,6 @@ export declare namespace Brand { type BrandRetrieveByIsinResponse as BrandRetrieveByIsinResponse, type BrandRetrieveByNameResponse as BrandRetrieveByNameResponse, type BrandRetrieveByTickerResponse as BrandRetrieveByTickerResponse, - type BrandRetrieveNaicsResponse as BrandRetrieveNaicsResponse, type BrandRetrieveSimplifiedResponse as BrandRetrieveSimplifiedResponse, type BrandWebScrapeHTMLResponse as BrandWebScrapeHTMLResponse, type BrandWebScrapeImagesResponse as BrandWebScrapeImagesResponse, @@ -7108,7 +7029,6 @@ export declare namespace Brand { type BrandRetrieveByIsinParams as BrandRetrieveByIsinParams, type BrandRetrieveByNameParams as BrandRetrieveByNameParams, type BrandRetrieveByTickerParams as BrandRetrieveByTickerParams, - type BrandRetrieveNaicsParams as BrandRetrieveNaicsParams, type BrandRetrieveSimplifiedParams as BrandRetrieveSimplifiedParams, type BrandWebScrapeHTMLParams as BrandWebScrapeHTMLParams, type BrandWebScrapeImagesParams as BrandWebScrapeImagesParams, diff --git a/src/resources/index.ts b/src/resources/index.ts index 97308d9c..24b951d7 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -13,7 +13,6 @@ export { type BrandRetrieveByIsinResponse, type BrandRetrieveByNameResponse, type BrandRetrieveByTickerResponse, - type BrandRetrieveNaicsResponse, type BrandRetrieveSimplifiedResponse, type BrandWebScrapeHTMLResponse, type BrandWebScrapeImagesResponse, @@ -30,7 +29,6 @@ export { type BrandRetrieveByIsinParams, type BrandRetrieveByNameParams, type BrandRetrieveByTickerParams, - type BrandRetrieveNaicsParams, type BrandRetrieveSimplifiedParams, type BrandWebScrapeHTMLParams, type BrandWebScrapeImagesParams, diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index cefbdbf8..a5213270 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -270,28 +270,6 @@ describe('resource brand', () => { }); }); - // Mock server tests are disabled - test.skip('retrieveNaics: only required params', async () => { - const responsePromise = client.brand.retrieveNaics({ input: 'input' }); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); - - // Mock server tests are disabled - test.skip('retrieveNaics: required and optional params', async () => { - const response = await client.brand.retrieveNaics({ - input: 'input', - maxResults: 1, - minResults: 1, - timeoutMS: 1000, - }); - }); - // Mock server tests are disabled test.skip('retrieveSimplified: only required params', async () => { const responsePromise = client.brand.retrieveSimplified({ domain: 'domain' }); From 1156b211aed4d8969ac4471d6b1c4079437198c5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:20:32 +0000 Subject: [PATCH 027/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f73f1bc1..57b9c339 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-071c7e9274f7e2f76732f22559fe8b4b75043a73c2c4af74ad2cc429d4bae357.yml -openapi_spec_hash: e7c47fbf61de6e2e9339f1dbb428cb8e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-13cb1b1b133273b7f4a26ff8772f162417a05342c56bfe26ec427bba0d54c8c3.yml +openapi_spec_hash: 45b57e0ecd3ab113e260ed2329ef5fa2 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 4dba2473d0657c9a9dc8f11647e94ef15e09565a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 17:36:18 +0000 Subject: [PATCH 028/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 57b9c339..53e55d8b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-13cb1b1b133273b7f4a26ff8772f162417a05342c56bfe26ec427bba0d54c8c3.yml -openapi_spec_hash: 45b57e0ecd3ab113e260ed2329ef5fa2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-356ccbb6bb3c12841b88bd036ef68cc2d5ee48d0bec0ccc4f50479ad4dbb5993.yml +openapi_spec_hash: f9ba30cd05421a6bef83f86d1c96bb82 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 65b0a202fddb6cc91d6af6c3baa02ef48fd8085b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 18:04:30 +0000 Subject: [PATCH 029/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 4 ++-- src/resources/brand.ts | 6 ++++++ tests/api-resources/brand.test.ts | 6 +++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 53e55d8b..0a349a13 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-356ccbb6bb3c12841b88bd036ef68cc2d5ee48d0bec0ccc4f50479ad4dbb5993.yml -openapi_spec_hash: f9ba30cd05421a6bef83f86d1c96bb82 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-b6262c6c346b4e4c6db18bc0c74585bb0b1d8f239048e893e76de2fcfd15ce01.yml +openapi_spec_hash: 157593d2318122199aedd86d7755f941 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index e948ca6f..5c02d580 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -698,11 +698,11 @@ const EMBEDDED_METHODS: MethodEntry[] = [ description: "Crawl an entire website's sitemap and return all discovered page URLs.", stainlessPath: '(resource) brand > (method) web_scrape_sitemap', qualified: 'client.brand.webScrapeSitemap', - params: ['domain: string;', 'maxLinks?: number;'], + params: ['domain: string;', 'maxLinks?: number;', 'urlRegex?: string;'], response: '{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }', markdown: - "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number, urlRegex?: string): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\n\n- `urlRegex?: string`\n Optional RE2-compatible regex pattern. Only URLs matching this pattern are returned and counted against maxLinks.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index f061f5c2..e7128f39 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -6998,6 +6998,12 @@ export interface BrandWebScrapeSitemapParams { * Minimum is 1, maximum is 100,000. */ maxLinks?: number; + + /** + * Optional RE2-compatible regex pattern. Only URLs matching this pattern are + * returned and counted against maxLinks. + */ + urlRegex?: string; } export declare namespace Brand { diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index a5213270..8cd9fb75 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -359,6 +359,10 @@ describe('resource brand', () => { // Mock server tests are disabled test.skip('webScrapeSitemap: required and optional params', async () => { - const response = await client.brand.webScrapeSitemap({ domain: 'domain', maxLinks: 1 }); + const response = await client.brand.webScrapeSitemap({ + domain: 'domain', + maxLinks: 1, + urlRegex: '^https?://[^/]+/blog/', + }); }); }); From 3262b7226e81f25d8f7ebe9aad1b5974827ddc12 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:44:13 +0000 Subject: [PATCH 030/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0a349a13..069181b4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-b6262c6c346b4e4c6db18bc0c74585bb0b1d8f239048e893e76de2fcfd15ce01.yml -openapi_spec_hash: 157593d2318122199aedd86d7755f941 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-9515e3e36a3c0be3fdd397d0e2934cf9c2accbe74b04711dcccb107ced266329.yml +openapi_spec_hash: 9409c01546e85f69aba881fb1d34c061 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 3084086cb5f62d71f1be21a5d4ef07aca2fc7523 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 03:38:50 +0000 Subject: [PATCH 031/100] chore(internal): update docs ordering --- packages/mcp-server/src/local-docs-search.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 5c02d580..ba4fd91c 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -734,14 +734,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ const EMBEDDED_READMES: { language: string; content: string }[] = [ { - language: 'python', + language: 'java', content: - '# Brand Dev Python API library\n\n\n[![PyPI version](https://img.shields.io/pypi/v/brand.dev.svg?label=pypi%20(stable))](https://pypi.org/project/brand.dev/)\n\nThe Brand Dev Python library provides convenient access to the Brand Dev REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install brand.dev\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\n\nbrand = client.brand.retrieve(\n domain="REPLACE_ME",\n)\nprint(brand.brand)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `BRAND_DEV_API_KEY="My API Key"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncBrandDev` instead of `BrandDev` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom brand.dev import AsyncBrandDev\n\nclient = AsyncBrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n brand = await client.brand.retrieve(\n domain="REPLACE_ME",\n )\n print(brand.brand)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install brand.dev[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom brand.dev import DefaultAioHttpClient\nfrom brand.dev import AsyncBrandDev\n\nasync def main() -> None:\n async with AsyncBrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n brand = await client.brand.retrieve(\n domain="REPLACE_ME",\n )\n print(brand.brand)\n\nasyncio.run(main())\n```\n\n\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom brand.dev import BrandDev\n\nclient = BrandDev()\n\nresponse = client.brand.ai_query(\n data_to_extract=[{\n "datapoint_description": "datapoint_description",\n "datapoint_example": "datapoint_example",\n "datapoint_name": "datapoint_name",\n "datapoint_type": "text",\n }],\n domain="domain",\n specific_pages={},\n)\nprint(response.specific_pages)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `brand.dev.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `brand.dev.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `brand.dev.APIError`.\n\n```python\nimport brand.dev\nfrom brand.dev import BrandDev\n\nclient = BrandDev()\n\ntry:\n client.brand.retrieve(\n domain="REPLACE_ME",\n )\nexcept brand.dev.APIConnectionError as e:\n print("The server could not be reached")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept brand.dev.RateLimitError as e:\n print("A 429 status code was received; we should back off a bit.")\nexcept brand.dev.APIStatusError as e:\n print("Another non-200-range status code was received")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 2 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom brand.dev import BrandDev\n\n# Configure the default for all requests:\nclient = BrandDev(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).brand.retrieve(\n domain="REPLACE_ME",\n)\n```\n\n### Timeouts\n\nBy default requests time out after 1 minute. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom brand.dev import BrandDev\n\n# Configure the default for all requests:\nclient = BrandDev(\n # 20 seconds (default is 1 minute)\n timeout=20.0,\n)\n\n# More granular control:\nclient = BrandDev(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).brand.retrieve(\n domain="REPLACE_ME",\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `BRAND_DEV_LOG` to `info`.\n\n```shell\n$ export BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if \'my_field\' not in response.model_fields_set:\n print(\'Got json like {}, without a "my_field" key present at all.\')\n else:\n print(\'Got json like {"my_field": null}.\')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom brand.dev import BrandDev\n\nclient = BrandDev()\nresponse = client.brand.with_raw_response.retrieve(\n domain="REPLACE_ME",\n)\nprint(response.headers.get(\'X-My-Header\'))\n\nbrand = response.parse() # get the object that `brand.retrieve()` would have returned\nprint(brand.brand)\n```\n\nThese methods return an [`APIResponse`](https://github.com/context-dot-dev/deprecated-brand-python-sdk/tree/main/src/brand/dev/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/context-dot-dev/deprecated-brand-python-sdk/tree/main/src/brand/dev/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.brand.with_streaming_response.retrieve(\n domain="REPLACE_ME",\n) as response :\n print(response.headers.get(\'X-My-Header\'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n "/foo",\n cast_to=httpx.Response,\n body={"my_param": True},\n)\n\nprint(response.headers.get("x-foo"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom brand.dev import BrandDev, DefaultHttpxClient\n\nclient = BrandDev(\n # Or use the `BRAND_DEV_BASE_URL` env var\n base_url="http://my.test.server.example.com:8083",\n http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom brand.dev import BrandDev\n\nwith BrandDev() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-python-sdk/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you\'ve upgraded to the latest version but aren\'t seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport brand.dev\nprint(brand.dev.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', + '# Brand Dev Java API Library\n\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.0.1)\n[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1)\n\n\nThe Brand Dev Java SDK provides convenient access to the [Brand Dev REST API](https://docs.context.dev/) from applications written in Java.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1).\n\n\n\n## Installation\n\n\n\n### Gradle\n\n~~~kotlin\nimplementation("com.branddev.api:brand-dev-java:0.0.1")\n~~~\n\n### Maven\n\n~~~xml\n\n com.branddev.api\n brand-dev-java\n 0.0.1\n\n~~~\n\n\n\n## Requirements\n\nThis library requires Java 8 or later.\n\n## Usage\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nBrandRetrieveResponse brand = client.brand().retrieve(params);\n```\n\n## Client configuration\n\nConfigure the client using system properties or environment variables:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n```\n\nOr manually:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .apiKey("My API Key")\n .build();\n```\n\nOr using a combination of the two approaches:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n // Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n // Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\n .fromEnv()\n .apiKey("My API Key")\n .build();\n```\n\nSee this table for the available options:\n\n| Setter | System property | Environment variable | Required | Default value |\n| --------- | ------------------ | -------------------- | -------- | ---------------------------- |\n| `apiKey` | `branddev.apiKey` | `BRAND_DEV_API_KEY` | true | - |\n| `baseUrl` | `branddev.baseUrl` | `BRAND_DEV_BASE_URL` | true | `"https://api.brand.dev/v1"` |\n\nSystem properties take precedence over environment variables.\n\n> [!TIP]\n> Don\'t create more than one client in the same application. Each client has a connection pool and\n> thread pools, which are more efficient to share between requests.\n\n### Modifying configuration\n\nTo temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\n\nBrandDevClient clientWithOptions = client.withOptions(optionsBuilder -> {\n optionsBuilder.baseUrl("https://example.com");\n optionsBuilder.maxRetries(42);\n});\n```\n\nThe `withOptions()` method does not affect the original client or service.\n\n## Requests and responses\n\nTo send a request to the Brand Dev API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.\n\nFor example, `client.brand().retrieve(...)` should be called with an instance of `BrandRetrieveParams`, and it will return an instance of `BrandRetrieveResponse`.\n\n## Immutability\n\nEach class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.\n\nEach class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.\n\nBecause each class is immutable, builder modification will _never_ affect already built class instances.\n\n## Asynchronous execution\n\nThe default client is synchronous. To switch to asynchronous execution, call the `async()` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.async().brand().retrieve(params);\n```\n\nOr create an asynchronous client from the beginning:\n\n```java\nimport com.branddev.api.client.BrandDevClientAsync;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClientAsync;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClientAsync client = BrandDevOkHttpClientAsync.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.brand().retrieve(params);\n```\n\nThe asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.\n\n\n\n\n\n\n\n## Raw responses\n\nThe SDK defines methods that deserialize responses into instances of Java classes. However, these methods don\'t provide access to the response headers, status code, or the raw response body.\n\nTo access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:\n\n```java\nimport com.branddev.api.core.http.Headers;\nimport com.branddev.api.core.http.HttpResponseFor;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nHttpResponseFor brand = client.brand().withRawResponse().retrieve(params);\n\nint statusCode = brand.statusCode();\nHeaders headers = brand.headers();\n```\n\nYou can still deserialize the response into an instance of a Java class if needed:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse parsedBrand = brand.parse();\n```\n\n## Error handling\n\nThe SDK throws custom unchecked exception types:\n\n- [`BrandDevServiceException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:\n\n | Status | Exception |\n | ------ | -------------------------------------------------- |\n | 400 | [`BadRequestException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BadRequestException.kt) |\n | 401 | [`UnauthorizedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnauthorizedException.kt) |\n | 403 | [`PermissionDeniedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/PermissionDeniedException.kt) |\n | 404 | [`NotFoundException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/NotFoundException.kt) |\n | 422 | [`UnprocessableEntityException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnprocessableEntityException.kt) |\n | 429 | [`RateLimitException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/RateLimitException.kt) |\n | 5xx | [`InternalServerException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/InternalServerException.kt) |\n | others | [`UnexpectedStatusCodeException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnexpectedStatusCodeException.kt) |\n\n- [`BrandDevIoException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevIoException.kt): I/O networking errors.\n\n- [`BrandDevRetryableException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevRetryableException.kt): Generic error indicating a failure that could be retried by the client.\n\n- [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that\'s supposed to be required, but the API unexpectedly omitted it from the response.\n\n- [`BrandDevException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.\n\n\n\n## Logging\n\nThe SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).\n\nEnable logging by setting the `BRAND_DEV_LOG` environment variable to `info`:\n\n```sh\nexport BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging:\n\n```sh\nexport BRAND_DEV_LOG=debug\n```\n\n## ProGuard and R8\n\nAlthough the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `brand-dev-java-core` is published with a [configuration file](brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).\n\nProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.\n\n\n\n\n\n## Jackson\n\nThe SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.\n\nThe SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).\n\nIf the SDK threw an exception, but you\'re _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt).\n\n> [!CAUTION]\n> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.\n\nAlso note that there are bugs in older Jackson versions that can affect the SDK. We don\'t work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead.\n\n## Network options\n\n### Retries\n\nThe SDK automatically retries 2 times by default, with a short exponential backoff between requests.\n\nOnly the following error types are retried:\n- Connection errors (for example, due to a network connectivity problem)\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- 5xx Internal\n\nThe API may also explicitly instruct the SDK to retry or not retry a request.\n\nTo set a custom number of retries, configure the client using the `maxRetries` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .maxRetries(4)\n .build();\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default.\n\nTo set a custom timeout, configure the method call using the `timeout` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .timeout(Duration.ofSeconds(30))\n .build();\n```\n\n### Proxies\n\nTo route requests through a proxy, configure the client using the `proxy` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(new Proxy(\n Proxy.Type.HTTP, new InetSocketAddress(\n "https://example.com", 8080\n )\n ))\n .build();\n```\n\n### Connection pooling\n\nTo customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.\n .maxIdleConnections(10)\n .keepAliveDuration(Duration.ofMinutes(2))\n .build();\n```\n\nIf both options are unset, OkHttp\'s default connection pool settings are used.\n\n### HTTPS\n\n> [!NOTE]\n> Most applications should not call these methods, and instead use the system defaults. The defaults include\n> special optimizations that can be lost if the implementations are modified.\n\nTo configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.\n .sslSocketFactory(yourSSLSocketFactory)\n .trustManager(yourTrustManager)\n .hostnameVerifier(yourHostnameVerifier)\n .build();\n```\n\n\n\n### Custom HTTP client\n\nThe SDK consists of three artifacts:\n- `brand-dev-java-core`\n - Contains core SDK logic\n - Does not depend on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClient.kt), [`BrandDevClientAsync`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsync.kt), [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt), and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), all of which can work with any HTTP client\n- `brand-dev-java-client-okhttp`\n - Depends on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) and [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), which provide a way to construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), respectively, using OkHttp\n- `brand-dev-java`\n - Depends on and exposes the APIs of both `brand-dev-java-core` and `brand-dev-java-client-okhttp`\n - Does not have its own logic\n\nThis structure allows replacing the SDK\'s default HTTP client without pulling in unnecessary dependencies.\n\n#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)\n\n> [!TIP]\n> Try the available [network options](#network-options) before replacing the default client.\n\nTo use a customized `OkHttpClient`:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Copy `brand-dev-java-client-okhttp`\'s [`OkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/OkHttpClient.kt) class into your code and customize it\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your customized client\n\n### Completely custom HTTP client\n\nTo use a completely custom HTTP client:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Write a class that implements the [`HttpClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/http/HttpClient.kt) interface\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your new client class\n\n## Undocumented API functionality\n\nThe SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.\n\n### Parameters\n\nTo set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .putAdditionalHeader("Secret-Header", "42")\n .putAdditionalQueryParam("secret_query_param", "42")\n .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))\n .build();\n```\n\nThese can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.\n\nTo set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\n\nBrandAiQueryParams params = BrandAiQueryParams.builder()\n .specificPages(BrandAiQueryParams.SpecificPages.builder()\n .putAdditionalProperty("secretProperty", JsonValue.from("42"))\n .build())\n .build();\n```\n\nThese properties can be accessed on the nested built object later using the `_additionalProperties()` method.\n\nTo set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) object to its setter:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\n```\n\nThe most straightforward way to create a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) is using its `from(...)` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.List;\nimport java.util.Map;\n\n// Create primitive JSON values\nJsonValue nullValue = JsonValue.from(null);\nJsonValue booleanValue = JsonValue.from(true);\nJsonValue numberValue = JsonValue.from(42);\nJsonValue stringValue = JsonValue.from("Hello World!");\n\n// Create a JSON array value equivalent to `["Hello", "World"]`\nJsonValue arrayValue = JsonValue.from(List.of(\n "Hello", "World"\n));\n\n// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`\nJsonValue objectValue = JsonValue.from(Map.of(\n "a", 1,\n "b", 2\n));\n\n// Create an arbitrarily nested JSON equivalent to:\n// {\n// "a": [1, 2],\n// "b": [3, 4]\n// }\nJsonValue complexValue = JsonValue.from(Map.of(\n "a", List.of(\n 1, 2\n ),\n "b", List.of(\n 3, 4\n )\n));\n```\n\nNormally a `Builder` class\'s `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.\n\nTo forcibly omit a required parameter or property, pass [`JsonMissing`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt):\n\n```java\nimport com.branddev.api.core.JsonMissing;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain(JsonMissing.of())\n .build();\n```\n\n### Response properties\n\nTo access undocumented response properties, call the `_additionalProperties()` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.Map;\n\nMap additionalProperties = client.brand().retrieve(params)._additionalProperties();\nJsonValue secretPropertyValue = additionalProperties.get("secretProperty");\n\nString result = secretPropertyValue.accept(new JsonValue.Visitor<>() {\n @Override\n public String visitNull() {\n return "It\'s null!";\n }\n\n @Override\n public String visitBoolean(boolean value) {\n return "It\'s a boolean!";\n }\n\n @Override\n public String visitNumber(Number value) {\n return "It\'s a number!";\n }\n\n // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`\n // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden\n});\n```\n\nTo access a property\'s raw JSON value, which may be undocumented, call its `_` prefixed method:\n\n```java\nimport com.branddev.api.core.JsonField;\nimport java.util.Optional;\n\nJsonField field = client.brand().retrieve(params)._field();\n\nif (field.isMissing()) {\n // The property is absent from the JSON response\n} else if (field.isNull()) {\n // The property was set to literal null\n} else {\n // Check if value was provided as a string\n // Other methods include `asNumber()`, `asBoolean()`, etc.\n Optional jsonString = field.asString();\n\n // Try to deserialize into a custom type\n MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class);\n}\n```\n\n### Response validation\n\nIn rare cases, the API may return a response that doesn\'t match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.\n\nBy default, the SDK will not throw an exception in this case. It will throw [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt) only if you directly access the property.\n\nIf you would prefer to check that the response is completely well-typed upfront, then either call `validate()`:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(params).validate();\n```\n\nOr configure the method call to validate the response using the `responseValidation` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().responseValidation(true).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .responseValidation(true)\n .build();\n```\n\n## FAQ\n\n### Why don\'t you use plain `enum` classes?\n\nJava `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.\n\n### Why do you represent fields using `JsonField` instead of just plain `T`?\n\nUsing `JsonField` enables a few features:\n\n- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)\n- Lazily [validating the API response against the expected shape](#response-validation)\n- Representing absent vs explicitly null values\n\n### Why don\'t you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?\n\nIt is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don\'t want to introduce a breaking change every time we add a field to a class.\n\n### Why don\'t you use checked exceptions?\n\nChecked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.\n\nChecked exceptions:\n\n- Are verbose to handle\n- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error\n- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)\n- Don\'t play well with lambdas (also due to the function coloring problem)\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-java-sdk/issues) with questions, bugs, or suggestions.\n', }, { - language: 'typescript', + language: 'python', content: - "# Brand Dev TypeScript API Library\n\n[![NPM version](https://img.shields.io/npm/v/brand.dev.svg?label=npm%20(stable))](https://npmjs.org/package/brand.dev) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/brand.dev)\n\nThis library provides convenient access to the Brand Dev REST API from server-side TypeScript or JavaScript.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). The full API of this library can be found in [api.md](api.md).\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n```sh\nnpm install brand.dev\n```\n\n\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n\n```js\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst brand = await client.brand.retrieve({ domain: 'REPLACE_ME' });\n\nconsole.log(brand.brand);\n```\n\n\n\n### Request & Response types\n\nThis library includes TypeScript definitions for all request params and response fields. You may import and use them like so:\n\n\n```ts\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst params: BrandDev.BrandRetrieveParams = { domain: 'REPLACE_ME' };\nconst brand: BrandDev.BrandRetrieveResponse = await client.brand.retrieve(params);\n```\n\nDocumentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.\n\n\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API,\nor if the API returns a non-success status code (i.e., 4xx or 5xx response),\na subclass of `APIError` will be thrown:\n\n\n```ts\nconst brand = await client.brand.retrieve({ domain: 'REPLACE_ME' }).catch(async (err) => {\n if (err instanceof BrandDev.APIError) {\n console.log(err.status); // 400\n console.log(err.name); // BadRequestError\n console.log(err.headers); // {server: 'nginx', ...}\n } else {\n throw err;\n }\n});\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors will all be retried by default.\n\nYou can use the `maxRetries` option to configure or disable this:\n\n\n```js\n// Configure the default for all requests:\nconst client = new BrandDev({\n maxRetries: 0, // default is 2\n});\n\n// Or, configure per-request:\nawait client.brand.retrieve({ domain: 'REPLACE_ME' }, {\n maxRetries: 5,\n});\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default. You can configure this with a `timeout` option:\n\n\n```ts\n// Configure the default for all requests:\nconst client = new BrandDev({\n timeout: 20 * 1000, // 20 seconds (default is 1 minute)\n});\n\n// Override per-request:\nawait client.brand.retrieve({ domain: 'REPLACE_ME' }, {\n timeout: 5 * 1000,\n});\n```\n\nOn timeout, an `APIConnectionTimeoutError` is thrown.\n\nNote that requests which time out will be [retried twice by default](#retries).\n\n\n\n\n\n## Advanced Usage\n\n### Accessing raw Response data (e.g., headers)\n\nThe \"raw\" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.\nThis method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic.\n\nYou can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.\nUnlike `.asResponse()` this method consumes the body, returning once it is parsed.\n\n\n```ts\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieve({ domain: 'REPLACE_ME' }).asResponse();\nconsole.log(response.headers.get('X-My-Header'));\nconsole.log(response.statusText); // access the underlying Response object\n\nconst { data: brand, response: raw } = await client.brand\n .retrieve({ domain: 'REPLACE_ME' })\n .withResponse();\nconsole.log(raw.headers.get('X-My-Header'));\nconsole.log(brand.brand);\n```\n\n### Logging\n\n> [!IMPORTANT]\n> All log messages are intended for debugging only. The format and content of log messages\n> may change between releases.\n\n#### Log levels\n\nThe log level can be configured in two ways:\n\n1. Via the `BRAND_DEV_LOG` environment variable\n2. Using the `logLevel` client option (overrides the environment variable if set)\n\n```ts\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n logLevel: 'debug', // Show all log messages\n});\n```\n\nAvailable log levels, from most to least verbose:\n\n- `'debug'` - Show debug messages, info, warnings, and errors\n- `'info'` - Show info messages, warnings, and errors\n- `'warn'` - Show warnings and errors (default)\n- `'error'` - Show only errors\n- `'off'` - Disable all logging\n\nAt the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies.\nSome authentication-related headers are redacted, but sensitive data in request and response bodies\nmay still be visible.\n\n#### Custom logger\n\nBy default, this library logs to `globalThis.console`. You can also provide a custom logger.\nMost logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue.\n\nWhen providing a custom logger, the `logLevel` option still controls which messages are emitted, messages\nbelow the configured level will not be sent to your logger.\n\n```ts\nimport BrandDev from 'brand.dev';\nimport pino from 'pino';\n\nconst logger = pino();\n\nconst client = new BrandDev({\n logger: logger.child({ name: 'BrandDev' }),\n logLevel: 'debug', // Send all messages to pino, allowing it to filter\n});\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.\nOptions on the client, such as retries, will be respected when making these requests.\n\n```ts\nawait client.post('/some/path', {\n body: { some_prop: 'foo' },\n query: { some_query_arg: 'bar' },\n});\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented\nparameter. This library doesn't validate at runtime that the request matches the type, so any extra values you\nsend will be sent as-is.\n\n```ts\nclient.brand.retrieve({\n // ...\n // @ts-expect-error baz is not yet public\n baz: 'undocumented option',\n});\n```\n\nFor requests with the `GET` verb, any extra params will be in the query, all other requests will send the\nextra param in the body.\n\nIf you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may access the response object with `// @ts-expect-error` on\nthe response object, or cast the response object to the requisite type. Like the request params, we do not\nvalidate or strip extra properties from the response from the API.\n\n### Customizing the fetch client\n\nBy default, this library expects a global `fetch` function is defined.\n\nIf you want to use a different `fetch` function, you can either polyfill the global:\n\n```ts\nimport fetch from 'my-fetch';\n\nglobalThis.fetch = fetch;\n```\n\nOr pass it to the client:\n\n```ts\nimport BrandDev from 'brand.dev';\nimport fetch from 'my-fetch';\n\nconst client = new BrandDev({ fetch });\n```\n\n### Fetch options\n\nIf you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.)\n\n```ts\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n fetchOptions: {\n // `RequestInit` options\n },\n});\n```\n\n#### Configuring proxies\n\nTo modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy\noptions to requests:\n\n **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]\n\n```ts\nimport BrandDev from 'brand.dev';\nimport * as undici from 'undici';\n\nconst proxyAgent = new undici.ProxyAgent('http://localhost:8888');\nconst client = new BrandDev({\n fetchOptions: {\n dispatcher: proxyAgent,\n },\n});\n```\n\n **Bun** [[docs](https://bun.sh/guides/http/proxy)]\n\n```ts\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n fetchOptions: {\n proxy: 'http://localhost:8888',\n },\n});\n```\n\n **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]\n\n```ts\nimport BrandDev from 'npm:brand.dev';\n\nconst httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });\nconst client = new BrandDev({\n fetchOptions: {\n client: httpClient,\n },\n});\n```\n\n## Frequently Asked Questions\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-typescript-sdk/issues) with questions, bugs, or suggestions.\n\n## Requirements\n\nTypeScript >= 4.9 is supported.\n\nThe following runtimes are supported:\n\n- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)\n- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.\n- Deno v1.28.0 or higher.\n- Bun 1.0 or later.\n- Cloudflare Workers.\n- Vercel Edge Runtime.\n- Jest 28 or greater with the `\"node\"` environment (`\"jsdom\"` is not supported at this time).\n- Nitro v2.6 or greater.\n\nNote that React Native is not supported at this time.\n\nIf you are interested in other runtime environments, please open or upvote an issue on GitHub.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n", + '# Brand Dev Python API library\n\n\n[![PyPI version](https://img.shields.io/pypi/v/brand.dev.svg?label=pypi%20(stable))](https://pypi.org/project/brand.dev/)\n\nThe Brand Dev Python library provides convenient access to the Brand Dev REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install brand.dev\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\n\nbrand = client.brand.retrieve(\n domain="REPLACE_ME",\n)\nprint(brand.brand)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `BRAND_DEV_API_KEY="My API Key"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncBrandDev` instead of `BrandDev` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom brand.dev import AsyncBrandDev\n\nclient = AsyncBrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n brand = await client.brand.retrieve(\n domain="REPLACE_ME",\n )\n print(brand.brand)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install brand.dev[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom brand.dev import DefaultAioHttpClient\nfrom brand.dev import AsyncBrandDev\n\nasync def main() -> None:\n async with AsyncBrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n brand = await client.brand.retrieve(\n domain="REPLACE_ME",\n )\n print(brand.brand)\n\nasyncio.run(main())\n```\n\n\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom brand.dev import BrandDev\n\nclient = BrandDev()\n\nresponse = client.brand.ai_query(\n data_to_extract=[{\n "datapoint_description": "datapoint_description",\n "datapoint_example": "datapoint_example",\n "datapoint_name": "datapoint_name",\n "datapoint_type": "text",\n }],\n domain="domain",\n specific_pages={},\n)\nprint(response.specific_pages)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `brand.dev.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `brand.dev.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `brand.dev.APIError`.\n\n```python\nimport brand.dev\nfrom brand.dev import BrandDev\n\nclient = BrandDev()\n\ntry:\n client.brand.retrieve(\n domain="REPLACE_ME",\n )\nexcept brand.dev.APIConnectionError as e:\n print("The server could not be reached")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept brand.dev.RateLimitError as e:\n print("A 429 status code was received; we should back off a bit.")\nexcept brand.dev.APIStatusError as e:\n print("Another non-200-range status code was received")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 2 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom brand.dev import BrandDev\n\n# Configure the default for all requests:\nclient = BrandDev(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).brand.retrieve(\n domain="REPLACE_ME",\n)\n```\n\n### Timeouts\n\nBy default requests time out after 1 minute. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom brand.dev import BrandDev\n\n# Configure the default for all requests:\nclient = BrandDev(\n # 20 seconds (default is 1 minute)\n timeout=20.0,\n)\n\n# More granular control:\nclient = BrandDev(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).brand.retrieve(\n domain="REPLACE_ME",\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `BRAND_DEV_LOG` to `info`.\n\n```shell\n$ export BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if \'my_field\' not in response.model_fields_set:\n print(\'Got json like {}, without a "my_field" key present at all.\')\n else:\n print(\'Got json like {"my_field": null}.\')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom brand.dev import BrandDev\n\nclient = BrandDev()\nresponse = client.brand.with_raw_response.retrieve(\n domain="REPLACE_ME",\n)\nprint(response.headers.get(\'X-My-Header\'))\n\nbrand = response.parse() # get the object that `brand.retrieve()` would have returned\nprint(brand.brand)\n```\n\nThese methods return an [`APIResponse`](https://github.com/context-dot-dev/deprecated-brand-python-sdk/tree/main/src/brand/dev/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/context-dot-dev/deprecated-brand-python-sdk/tree/main/src/brand/dev/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.brand.with_streaming_response.retrieve(\n domain="REPLACE_ME",\n) as response :\n print(response.headers.get(\'X-My-Header\'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n "/foo",\n cast_to=httpx.Response,\n body={"my_param": True},\n)\n\nprint(response.headers.get("x-foo"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom brand.dev import BrandDev, DefaultHttpxClient\n\nclient = BrandDev(\n # Or use the `BRAND_DEV_BASE_URL` env var\n base_url="http://my.test.server.example.com:8083",\n http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom brand.dev import BrandDev\n\nwith BrandDev() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-python-sdk/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you\'ve upgraded to the latest version but aren\'t seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport brand.dev\nprint(brand.dev.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', }, { language: 'ruby', @@ -749,9 +749,9 @@ const EMBEDDED_READMES: { language: string; content: string }[] = [ '# Brand Dev Ruby API library\n\nThe Brand Dev Ruby library provides convenient access to the Brand Dev REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/context-dot-dev/deprecated-brand-ruby-sdk#Sorbet) for usage with Sorbet. The standard library\'s `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nDocumentation for releases of this gem can be found [on RubyDoc](https://gemdocs.org/gems/brand.dev).\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/).\n\n## Installation\n\nTo use this gem, install via Bundler by adding the following to your application\'s `Gemfile`:\n\n\n\n```ruby\ngem "brand.dev", "~> 0.0.1"\n```\n\n\n\n## Usage\n\n```ruby\nrequire "bundler/setup"\nrequire "brand_dev"\n\nbrand_dev = BrandDev::Client.new(\n api_key: ENV["BRAND_DEV_API_KEY"] # This is the default and can be omitted\n)\n\nbrand = brand_dev.brand.retrieve(domain: "REPLACE_ME")\n\nputs(brand.brand)\n```\n\n\n\n\n\n\n\n### Handling errors\n\nWhen the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `BrandDev::Errors::APIError` will be thrown:\n\n```ruby\nbegin\n brand = brand_dev.brand.retrieve(domain: "REPLACE_ME")\nrescue BrandDev::Errors::APIConnectionError => e\n puts("The server could not be reached")\n puts(e.cause) # an underlying Exception, likely raised within `net/http`\nrescue BrandDev::Errors::RateLimitError => e\n puts("A 429 status code was received; we should back off a bit.")\nrescue BrandDev::Errors::APIStatusError => e\n puts("Another non-200-range status code was received")\n puts(e.status)\nend\n```\n\nError codes are as follows:\n\n| Cause | Error Type |\n| ---------------- | -------------------------- |\n| HTTP 400 | `BadRequestError` |\n| HTTP 401 | `AuthenticationError` |\n| HTTP 403 | `PermissionDeniedError` |\n| HTTP 404 | `NotFoundError` |\n| HTTP 409 | `ConflictError` |\n| HTTP 422 | `UnprocessableEntityError` |\n| HTTP 429 | `RateLimitError` |\n| HTTP >= 500 | `InternalServerError` |\n| Other HTTP error | `APIStatusError` |\n| Timeout | `APITimeoutError` |\n| Network error | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\n\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, >=500 Internal errors, and timeouts will all be retried by default.\n\nYou can use the `max_retries` option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nbrand_dev = BrandDev::Client.new(\n max_retries: 0 # default is 2\n)\n\n# Or, configure per-request:\nbrand_dev.brand.retrieve(domain: "REPLACE_ME", request_options: {max_retries: 5})\n```\n\n### Timeouts\n\nBy default, requests will time out after 60 seconds. You can use the timeout option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nbrand_dev = BrandDev::Client.new(\n timeout: nil # default is 60\n)\n\n# Or, configure per-request:\nbrand_dev.brand.retrieve(domain: "REPLACE_ME", request_options: {timeout: 5})\n```\n\nOn timeout, `BrandDev::Errors::APITimeoutError` is raised.\n\nNote that requests that time out are retried by default.\n\n## Advanced concepts\n\n### BaseModel\n\nAll parameter and response objects inherit from `BrandDev::Internal::Type::BaseModel`, which provides several conveniences, including:\n\n1. All fields, including unknown ones, are accessible with `obj[:prop]` syntax, and can be destructured with `obj => {prop: prop}` or pattern-matching syntax.\n\n2. Structural equivalence for equality; if two API calls return the same values, comparing the responses with == will return true.\n\n3. Both instances and the classes themselves can be pretty-printed.\n\n4. Helpers such as `#to_h`, `#deep_to_h`, `#to_json`, and `#to_yaml`.\n\n### Making custom or undocumented requests\n\n#### Undocumented properties\n\nYou can send undocumented parameters to any endpoint, and read undocumented response properties, like so:\n\nNote: the `extra_` parameters of the same name overrides the documented parameters.\n\n```ruby\nbrand =\n brand_dev.brand.retrieve(\n domain: "REPLACE_ME",\n request_options: {\n extra_query: {my_query_parameter: value},\n extra_body: {my_body_parameter: value},\n extra_headers: {"my-header": value}\n }\n )\n\nputs(brand[:my_undocumented_property])\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a request, as seen in the examples above.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on, you can make requests using `client.request`, like so:\n\n```ruby\nresponse = client.request(\n method: :post,\n path: \'/undocumented/endpoint\',\n query: {"dog": "woof"},\n headers: {"useful-header": "interesting-value"},\n body: {"hello": "world"}\n)\n```\n\n### Concurrency & connection pooling\n\nThe `BrandDev::Client` instances are threadsafe, but are only are fork-safe when there are no in-flight HTTP requests.\n\nEach instance of `BrandDev::Client` has its own HTTP connection pool with a default size of 99. As such, we recommend instantiating the client once per application in most settings.\n\nWhen all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout.\n\nUnless otherwise specified, other classes in the SDK do not have locks protecting their underlying data structure.\n\n## Sorbet\n\nThis library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitions, and has no dependency on sorbet-runtime.\n\nYou can provide typesafe request parameters like so:\n\n```ruby\nbrand_dev.brand.retrieve(domain: "REPLACE_ME")\n```\n\nOr, equivalently:\n\n```ruby\n# Hashes work, but are not typesafe:\nbrand_dev.brand.retrieve(domain: "REPLACE_ME")\n\n# You can also splat a full Params class:\nparams = BrandDev::BrandRetrieveParams.new(domain: "REPLACE_ME")\nbrand_dev.brand.retrieve(**params)\n```\n\n### Enums\n\nSince this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide "tagged symbols" instead, which is always a primitive at runtime:\n\n```ruby\n# :afrikaans\nputs(BrandDev::BrandRetrieveParams::ForceLanguage::AFRIKAANS)\n\n# Revealed type: `T.all(BrandDev::BrandRetrieveParams::ForceLanguage, Symbol)`\nT.reveal_type(BrandDev::BrandRetrieveParams::ForceLanguage::AFRIKAANS)\n```\n\nEnum parameters have a "relaxed" type, so you can either pass in enum constants or their literal value:\n\n```ruby\n# Using the enum constants preserves the tagged type information:\nbrand_dev.brand.retrieve(\n force_language: BrandDev::BrandRetrieveParams::ForceLanguage::AFRIKAANS,\n # …\n)\n\n# Literal values are also permissible:\nbrand_dev.brand.retrieve(\n force_language: :afrikaans,\n # …\n)\n```\n\n## Versioning\n\nThis package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions. As the library is in initial development and has a major version of `0`, APIs may change at any time.\n\nThis package considers improvements to the (non-runtime) `*.rbi` and `*.rbs` type definitions to be non-breaking changes.\n\n## Requirements\n\nRuby 3.2.0 or higher.\n\n## Contributing\n\nSee [the contributing documentation](https://github.com/context-dot-dev/deprecated-brand-ruby-sdk/tree/main/CONTRIBUTING.md).\n', }, { - language: 'java', + language: 'typescript', content: - '# Brand Dev Java API Library\n\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.0.1)\n[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1)\n\n\nThe Brand Dev Java SDK provides convenient access to the [Brand Dev REST API](https://docs.context.dev/) from applications written in Java.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1).\n\n\n\n## Installation\n\n\n\n### Gradle\n\n~~~kotlin\nimplementation("com.branddev.api:brand-dev-java:0.0.1")\n~~~\n\n### Maven\n\n~~~xml\n\n com.branddev.api\n brand-dev-java\n 0.0.1\n\n~~~\n\n\n\n## Requirements\n\nThis library requires Java 8 or later.\n\n## Usage\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nBrandRetrieveResponse brand = client.brand().retrieve(params);\n```\n\n## Client configuration\n\nConfigure the client using system properties or environment variables:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n```\n\nOr manually:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .apiKey("My API Key")\n .build();\n```\n\nOr using a combination of the two approaches:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n // Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n // Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\n .fromEnv()\n .apiKey("My API Key")\n .build();\n```\n\nSee this table for the available options:\n\n| Setter | System property | Environment variable | Required | Default value |\n| --------- | ------------------ | -------------------- | -------- | ---------------------------- |\n| `apiKey` | `branddev.apiKey` | `BRAND_DEV_API_KEY` | true | - |\n| `baseUrl` | `branddev.baseUrl` | `BRAND_DEV_BASE_URL` | true | `"https://api.brand.dev/v1"` |\n\nSystem properties take precedence over environment variables.\n\n> [!TIP]\n> Don\'t create more than one client in the same application. Each client has a connection pool and\n> thread pools, which are more efficient to share between requests.\n\n### Modifying configuration\n\nTo temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\n\nBrandDevClient clientWithOptions = client.withOptions(optionsBuilder -> {\n optionsBuilder.baseUrl("https://example.com");\n optionsBuilder.maxRetries(42);\n});\n```\n\nThe `withOptions()` method does not affect the original client or service.\n\n## Requests and responses\n\nTo send a request to the Brand Dev API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.\n\nFor example, `client.brand().retrieve(...)` should be called with an instance of `BrandRetrieveParams`, and it will return an instance of `BrandRetrieveResponse`.\n\n## Immutability\n\nEach class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.\n\nEach class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.\n\nBecause each class is immutable, builder modification will _never_ affect already built class instances.\n\n## Asynchronous execution\n\nThe default client is synchronous. To switch to asynchronous execution, call the `async()` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.async().brand().retrieve(params);\n```\n\nOr create an asynchronous client from the beginning:\n\n```java\nimport com.branddev.api.client.BrandDevClientAsync;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClientAsync;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClientAsync client = BrandDevOkHttpClientAsync.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.brand().retrieve(params);\n```\n\nThe asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.\n\n\n\n\n\n\n\n## Raw responses\n\nThe SDK defines methods that deserialize responses into instances of Java classes. However, these methods don\'t provide access to the response headers, status code, or the raw response body.\n\nTo access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:\n\n```java\nimport com.branddev.api.core.http.Headers;\nimport com.branddev.api.core.http.HttpResponseFor;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nHttpResponseFor brand = client.brand().withRawResponse().retrieve(params);\n\nint statusCode = brand.statusCode();\nHeaders headers = brand.headers();\n```\n\nYou can still deserialize the response into an instance of a Java class if needed:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse parsedBrand = brand.parse();\n```\n\n## Error handling\n\nThe SDK throws custom unchecked exception types:\n\n- [`BrandDevServiceException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:\n\n | Status | Exception |\n | ------ | -------------------------------------------------- |\n | 400 | [`BadRequestException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BadRequestException.kt) |\n | 401 | [`UnauthorizedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnauthorizedException.kt) |\n | 403 | [`PermissionDeniedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/PermissionDeniedException.kt) |\n | 404 | [`NotFoundException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/NotFoundException.kt) |\n | 422 | [`UnprocessableEntityException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnprocessableEntityException.kt) |\n | 429 | [`RateLimitException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/RateLimitException.kt) |\n | 5xx | [`InternalServerException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/InternalServerException.kt) |\n | others | [`UnexpectedStatusCodeException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnexpectedStatusCodeException.kt) |\n\n- [`BrandDevIoException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevIoException.kt): I/O networking errors.\n\n- [`BrandDevRetryableException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevRetryableException.kt): Generic error indicating a failure that could be retried by the client.\n\n- [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that\'s supposed to be required, but the API unexpectedly omitted it from the response.\n\n- [`BrandDevException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.\n\n\n\n## Logging\n\nThe SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).\n\nEnable logging by setting the `BRAND_DEV_LOG` environment variable to `info`:\n\n```sh\nexport BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging:\n\n```sh\nexport BRAND_DEV_LOG=debug\n```\n\n## ProGuard and R8\n\nAlthough the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `brand-dev-java-core` is published with a [configuration file](brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).\n\nProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.\n\n\n\n\n\n## Jackson\n\nThe SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.\n\nThe SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).\n\nIf the SDK threw an exception, but you\'re _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt).\n\n> [!CAUTION]\n> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.\n\nAlso note that there are bugs in older Jackson versions that can affect the SDK. We don\'t work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead.\n\n## Network options\n\n### Retries\n\nThe SDK automatically retries 2 times by default, with a short exponential backoff between requests.\n\nOnly the following error types are retried:\n- Connection errors (for example, due to a network connectivity problem)\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- 5xx Internal\n\nThe API may also explicitly instruct the SDK to retry or not retry a request.\n\nTo set a custom number of retries, configure the client using the `maxRetries` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .maxRetries(4)\n .build();\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default.\n\nTo set a custom timeout, configure the method call using the `timeout` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .timeout(Duration.ofSeconds(30))\n .build();\n```\n\n### Proxies\n\nTo route requests through a proxy, configure the client using the `proxy` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(new Proxy(\n Proxy.Type.HTTP, new InetSocketAddress(\n "https://example.com", 8080\n )\n ))\n .build();\n```\n\n### Connection pooling\n\nTo customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.\n .maxIdleConnections(10)\n .keepAliveDuration(Duration.ofMinutes(2))\n .build();\n```\n\nIf both options are unset, OkHttp\'s default connection pool settings are used.\n\n### HTTPS\n\n> [!NOTE]\n> Most applications should not call these methods, and instead use the system defaults. The defaults include\n> special optimizations that can be lost if the implementations are modified.\n\nTo configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.\n .sslSocketFactory(yourSSLSocketFactory)\n .trustManager(yourTrustManager)\n .hostnameVerifier(yourHostnameVerifier)\n .build();\n```\n\n\n\n### Custom HTTP client\n\nThe SDK consists of three artifacts:\n- `brand-dev-java-core`\n - Contains core SDK logic\n - Does not depend on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClient.kt), [`BrandDevClientAsync`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsync.kt), [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt), and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), all of which can work with any HTTP client\n- `brand-dev-java-client-okhttp`\n - Depends on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) and [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), which provide a way to construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), respectively, using OkHttp\n- `brand-dev-java`\n - Depends on and exposes the APIs of both `brand-dev-java-core` and `brand-dev-java-client-okhttp`\n - Does not have its own logic\n\nThis structure allows replacing the SDK\'s default HTTP client without pulling in unnecessary dependencies.\n\n#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)\n\n> [!TIP]\n> Try the available [network options](#network-options) before replacing the default client.\n\nTo use a customized `OkHttpClient`:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Copy `brand-dev-java-client-okhttp`\'s [`OkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/OkHttpClient.kt) class into your code and customize it\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your customized client\n\n### Completely custom HTTP client\n\nTo use a completely custom HTTP client:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Write a class that implements the [`HttpClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/http/HttpClient.kt) interface\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your new client class\n\n## Undocumented API functionality\n\nThe SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.\n\n### Parameters\n\nTo set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .putAdditionalHeader("Secret-Header", "42")\n .putAdditionalQueryParam("secret_query_param", "42")\n .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))\n .build();\n```\n\nThese can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.\n\nTo set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\n\nBrandAiQueryParams params = BrandAiQueryParams.builder()\n .specificPages(BrandAiQueryParams.SpecificPages.builder()\n .putAdditionalProperty("secretProperty", JsonValue.from("42"))\n .build())\n .build();\n```\n\nThese properties can be accessed on the nested built object later using the `_additionalProperties()` method.\n\nTo set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) object to its setter:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\n```\n\nThe most straightforward way to create a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) is using its `from(...)` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.List;\nimport java.util.Map;\n\n// Create primitive JSON values\nJsonValue nullValue = JsonValue.from(null);\nJsonValue booleanValue = JsonValue.from(true);\nJsonValue numberValue = JsonValue.from(42);\nJsonValue stringValue = JsonValue.from("Hello World!");\n\n// Create a JSON array value equivalent to `["Hello", "World"]`\nJsonValue arrayValue = JsonValue.from(List.of(\n "Hello", "World"\n));\n\n// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`\nJsonValue objectValue = JsonValue.from(Map.of(\n "a", 1,\n "b", 2\n));\n\n// Create an arbitrarily nested JSON equivalent to:\n// {\n// "a": [1, 2],\n// "b": [3, 4]\n// }\nJsonValue complexValue = JsonValue.from(Map.of(\n "a", List.of(\n 1, 2\n ),\n "b", List.of(\n 3, 4\n )\n));\n```\n\nNormally a `Builder` class\'s `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.\n\nTo forcibly omit a required parameter or property, pass [`JsonMissing`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt):\n\n```java\nimport com.branddev.api.core.JsonMissing;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain(JsonMissing.of())\n .build();\n```\n\n### Response properties\n\nTo access undocumented response properties, call the `_additionalProperties()` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.Map;\n\nMap additionalProperties = client.brand().retrieve(params)._additionalProperties();\nJsonValue secretPropertyValue = additionalProperties.get("secretProperty");\n\nString result = secretPropertyValue.accept(new JsonValue.Visitor<>() {\n @Override\n public String visitNull() {\n return "It\'s null!";\n }\n\n @Override\n public String visitBoolean(boolean value) {\n return "It\'s a boolean!";\n }\n\n @Override\n public String visitNumber(Number value) {\n return "It\'s a number!";\n }\n\n // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`\n // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden\n});\n```\n\nTo access a property\'s raw JSON value, which may be undocumented, call its `_` prefixed method:\n\n```java\nimport com.branddev.api.core.JsonField;\nimport java.util.Optional;\n\nJsonField field = client.brand().retrieve(params)._field();\n\nif (field.isMissing()) {\n // The property is absent from the JSON response\n} else if (field.isNull()) {\n // The property was set to literal null\n} else {\n // Check if value was provided as a string\n // Other methods include `asNumber()`, `asBoolean()`, etc.\n Optional jsonString = field.asString();\n\n // Try to deserialize into a custom type\n MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class);\n}\n```\n\n### Response validation\n\nIn rare cases, the API may return a response that doesn\'t match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.\n\nBy default, the SDK will not throw an exception in this case. It will throw [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt) only if you directly access the property.\n\nIf you would prefer to check that the response is completely well-typed upfront, then either call `validate()`:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(params).validate();\n```\n\nOr configure the method call to validate the response using the `responseValidation` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().responseValidation(true).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .responseValidation(true)\n .build();\n```\n\n## FAQ\n\n### Why don\'t you use plain `enum` classes?\n\nJava `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.\n\n### Why do you represent fields using `JsonField` instead of just plain `T`?\n\nUsing `JsonField` enables a few features:\n\n- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)\n- Lazily [validating the API response against the expected shape](#response-validation)\n- Representing absent vs explicitly null values\n\n### Why don\'t you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?\n\nIt is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don\'t want to introduce a breaking change every time we add a field to a class.\n\n### Why don\'t you use checked exceptions?\n\nChecked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.\n\nChecked exceptions:\n\n- Are verbose to handle\n- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error\n- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)\n- Don\'t play well with lambdas (also due to the function coloring problem)\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-java-sdk/issues) with questions, bugs, or suggestions.\n', + "# Brand Dev TypeScript API Library\n\n[![NPM version](https://img.shields.io/npm/v/brand.dev.svg?label=npm%20(stable))](https://npmjs.org/package/brand.dev) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/brand.dev)\n\nThis library provides convenient access to the Brand Dev REST API from server-side TypeScript or JavaScript.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). The full API of this library can be found in [api.md](api.md).\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n```sh\nnpm install brand.dev\n```\n\n\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n\n```js\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst brand = await client.brand.retrieve({ domain: 'REPLACE_ME' });\n\nconsole.log(brand.brand);\n```\n\n\n\n### Request & Response types\n\nThis library includes TypeScript definitions for all request params and response fields. You may import and use them like so:\n\n\n```ts\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst params: BrandDev.BrandRetrieveParams = { domain: 'REPLACE_ME' };\nconst brand: BrandDev.BrandRetrieveResponse = await client.brand.retrieve(params);\n```\n\nDocumentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.\n\n\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API,\nor if the API returns a non-success status code (i.e., 4xx or 5xx response),\na subclass of `APIError` will be thrown:\n\n\n```ts\nconst brand = await client.brand.retrieve({ domain: 'REPLACE_ME' }).catch(async (err) => {\n if (err instanceof BrandDev.APIError) {\n console.log(err.status); // 400\n console.log(err.name); // BadRequestError\n console.log(err.headers); // {server: 'nginx', ...}\n } else {\n throw err;\n }\n});\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors will all be retried by default.\n\nYou can use the `maxRetries` option to configure or disable this:\n\n\n```js\n// Configure the default for all requests:\nconst client = new BrandDev({\n maxRetries: 0, // default is 2\n});\n\n// Or, configure per-request:\nawait client.brand.retrieve({ domain: 'REPLACE_ME' }, {\n maxRetries: 5,\n});\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default. You can configure this with a `timeout` option:\n\n\n```ts\n// Configure the default for all requests:\nconst client = new BrandDev({\n timeout: 20 * 1000, // 20 seconds (default is 1 minute)\n});\n\n// Override per-request:\nawait client.brand.retrieve({ domain: 'REPLACE_ME' }, {\n timeout: 5 * 1000,\n});\n```\n\nOn timeout, an `APIConnectionTimeoutError` is thrown.\n\nNote that requests which time out will be [retried twice by default](#retries).\n\n\n\n\n\n## Advanced Usage\n\n### Accessing raw Response data (e.g., headers)\n\nThe \"raw\" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.\nThis method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic.\n\nYou can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.\nUnlike `.asResponse()` this method consumes the body, returning once it is parsed.\n\n\n```ts\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieve({ domain: 'REPLACE_ME' }).asResponse();\nconsole.log(response.headers.get('X-My-Header'));\nconsole.log(response.statusText); // access the underlying Response object\n\nconst { data: brand, response: raw } = await client.brand\n .retrieve({ domain: 'REPLACE_ME' })\n .withResponse();\nconsole.log(raw.headers.get('X-My-Header'));\nconsole.log(brand.brand);\n```\n\n### Logging\n\n> [!IMPORTANT]\n> All log messages are intended for debugging only. The format and content of log messages\n> may change between releases.\n\n#### Log levels\n\nThe log level can be configured in two ways:\n\n1. Via the `BRAND_DEV_LOG` environment variable\n2. Using the `logLevel` client option (overrides the environment variable if set)\n\n```ts\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n logLevel: 'debug', // Show all log messages\n});\n```\n\nAvailable log levels, from most to least verbose:\n\n- `'debug'` - Show debug messages, info, warnings, and errors\n- `'info'` - Show info messages, warnings, and errors\n- `'warn'` - Show warnings and errors (default)\n- `'error'` - Show only errors\n- `'off'` - Disable all logging\n\nAt the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies.\nSome authentication-related headers are redacted, but sensitive data in request and response bodies\nmay still be visible.\n\n#### Custom logger\n\nBy default, this library logs to `globalThis.console`. You can also provide a custom logger.\nMost logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue.\n\nWhen providing a custom logger, the `logLevel` option still controls which messages are emitted, messages\nbelow the configured level will not be sent to your logger.\n\n```ts\nimport BrandDev from 'brand.dev';\nimport pino from 'pino';\n\nconst logger = pino();\n\nconst client = new BrandDev({\n logger: logger.child({ name: 'BrandDev' }),\n logLevel: 'debug', // Send all messages to pino, allowing it to filter\n});\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.\nOptions on the client, such as retries, will be respected when making these requests.\n\n```ts\nawait client.post('/some/path', {\n body: { some_prop: 'foo' },\n query: { some_query_arg: 'bar' },\n});\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented\nparameter. This library doesn't validate at runtime that the request matches the type, so any extra values you\nsend will be sent as-is.\n\n```ts\nclient.brand.retrieve({\n // ...\n // @ts-expect-error baz is not yet public\n baz: 'undocumented option',\n});\n```\n\nFor requests with the `GET` verb, any extra params will be in the query, all other requests will send the\nextra param in the body.\n\nIf you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may access the response object with `// @ts-expect-error` on\nthe response object, or cast the response object to the requisite type. Like the request params, we do not\nvalidate or strip extra properties from the response from the API.\n\n### Customizing the fetch client\n\nBy default, this library expects a global `fetch` function is defined.\n\nIf you want to use a different `fetch` function, you can either polyfill the global:\n\n```ts\nimport fetch from 'my-fetch';\n\nglobalThis.fetch = fetch;\n```\n\nOr pass it to the client:\n\n```ts\nimport BrandDev from 'brand.dev';\nimport fetch from 'my-fetch';\n\nconst client = new BrandDev({ fetch });\n```\n\n### Fetch options\n\nIf you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.)\n\n```ts\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n fetchOptions: {\n // `RequestInit` options\n },\n});\n```\n\n#### Configuring proxies\n\nTo modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy\noptions to requests:\n\n **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]\n\n```ts\nimport BrandDev from 'brand.dev';\nimport * as undici from 'undici';\n\nconst proxyAgent = new undici.ProxyAgent('http://localhost:8888');\nconst client = new BrandDev({\n fetchOptions: {\n dispatcher: proxyAgent,\n },\n});\n```\n\n **Bun** [[docs](https://bun.sh/guides/http/proxy)]\n\n```ts\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n fetchOptions: {\n proxy: 'http://localhost:8888',\n },\n});\n```\n\n **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]\n\n```ts\nimport BrandDev from 'npm:brand.dev';\n\nconst httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });\nconst client = new BrandDev({\n fetchOptions: {\n client: httpClient,\n },\n});\n```\n\n## Frequently Asked Questions\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-typescript-sdk/issues) with questions, bugs, or suggestions.\n\n## Requirements\n\nTypeScript >= 4.9 is supported.\n\nThe following runtimes are supported:\n\n- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)\n- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.\n- Deno v1.28.0 or higher.\n- Bun 1.0 or later.\n- Cloudflare Workers.\n- Vercel Edge Runtime.\n- Jest 28 or greater with the `\"node\"` environment (`\"jsdom\"` is not supported at this time).\n- Nitro v2.6 or greater.\n\nNote that React Native is not supported at this time.\n\nIf you are interested in other runtime environments, please open or upvote an issue on GitHub.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n", }, ]; From 6b1838d94014d4ff073c38392820cfb868d2ee28 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 03:39:21 +0000 Subject: [PATCH 032/100] chore(internal): more robust bootstrap script --- scripts/bootstrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bootstrap b/scripts/bootstrap index a8b69ff3..2e315f53 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { echo -n "==> Install Homebrew dependencies? (y/N): " read -r response From 287c535fa0d8c86bfdbff51528d0a5ece71be76b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:55:15 +0000 Subject: [PATCH 033/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 069181b4..2008d73b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-9515e3e36a3c0be3fdd397d0e2934cf9c2accbe74b04711dcccb107ced266329.yml -openapi_spec_hash: 9409c01546e85f69aba881fb1d34c061 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-bad99401f1babc6e34ab94e1700768545292825447e43fecbbfe426ae89c594c.yml +openapi_spec_hash: 2b40ce701c90ae2cb9f89ee7b52bbf5b config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 0617a88b23443ea0bc13498ef589ee400ef432a1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 01:01:42 +0000 Subject: [PATCH 034/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 7 ++++--- src/resources/brand.ts | 14 ++++++++++++++ tests/api-resources/brand.test.ts | 7 ++++++- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2008d73b..21683637 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-bad99401f1babc6e34ab94e1700768545292825447e43fecbbfe426ae89c594c.yml -openapi_spec_hash: 2b40ce701c90ae2cb9f89ee7b52bbf5b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-5feeb635e8e8c4d52f5ab3e689888134427dae866a0c5264a31598a538673130.yml +openapi_spec_hash: 9619b7626bbad5468f41623726e229c9 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index ba4fd91c..f2361903 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -572,10 +572,10 @@ const EMBEDDED_METHODS: MethodEntry[] = [ description: 'Scrapes the given URL and returns the raw HTML content of the page.', stainlessPath: '(resource) brand > (method) web_scrape_html', qualified: 'client.brand.webScrapeHTML', - params: ['url: string;', 'maxAgeMs?: number;'], + params: ['url: string;', 'maxAgeMs?: number;', 'parsePDF?: boolean;'], response: '{ html: string; success: true; url: string; }', markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, maxAgeMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\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### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, maxAgeMs?: number, parsePDF?: boolean): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and returned wrapped in . When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -616,12 +616,13 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'includeImages?: boolean;', 'includeLinks?: boolean;', 'maxAgeMs?: number;', + 'parsePDF?: boolean;', 'shortenBase64Images?: boolean;', 'useMainContentOnly?: boolean;', ], response: '{ markdown: string; success: true; url: string; }', markdown: - "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, parsePDF?: boolean, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and converted to Markdown. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index e7128f39..0dfb135a 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -6942,6 +6942,13 @@ export interface BrandWebScrapeHTMLParams { * omitted. Max is 30 days (2592000000 ms). Set to 0 to always scrape fresh. */ maxAgeMs?: number; + + /** + * When true (default), PDF URLs are fetched and their text layer is extracted and + * returned wrapped in . When false, PDF URLs are skipped + * and a 400 WEBSITE_ACCESS_ERROR is returned. + */ + parsePDF?: boolean; } export interface BrandWebScrapeImagesParams { @@ -6975,6 +6982,13 @@ export interface BrandWebScrapeMdParams { */ maxAgeMs?: number; + /** + * When true (default), PDF URLs are fetched and their text layer is extracted and + * converted to Markdown. When false, PDF URLs are skipped and a 400 + * WEBSITE_ACCESS_ERROR is returned. + */ + parsePDF?: boolean; + /** * Shorten base64-encoded image data in the Markdown output */ diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 8cd9fb75..e413964d 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -301,7 +301,11 @@ describe('resource brand', () => { // Mock server tests are disabled test.skip('webScrapeHTML: required and optional params', async () => { - const response = await client.brand.webScrapeHTML({ url: 'https://example.com', maxAgeMs: 0 }); + const response = await client.brand.webScrapeHTML({ + url: 'https://example.com', + maxAgeMs: 0, + parsePDF: true, + }); }); // Mock server tests are disabled @@ -340,6 +344,7 @@ describe('resource brand', () => { includeImages: true, includeLinks: true, maxAgeMs: 0, + parsePDF: true, shortenBase64Images: true, useMainContentOnly: true, }); From a83efa13afc3f4f6b564dcba1eebf34e1308d388 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 01:56:01 +0000 Subject: [PATCH 035/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 6 +++--- src/resources/brand.ts | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 21683637..c2c1aed7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-5feeb635e8e8c4d52f5ab3e689888134427dae866a0c5264a31598a538673130.yml -openapi_spec_hash: 9619b7626bbad5468f41623726e229c9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-a79be9698f9c8908538102f0ea3ed43ce85be94c723f81ce3f7143b6dd394c62.yml +openapi_spec_hash: 840d5e6c9fd1710942bd61ab08f7f411 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index f2361903..44895cc3 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -495,7 +495,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ '{ domain: string; maxProducts?: number; timeoutMS?: number; } | { directUrl: string; maxProducts?: number; timeoutMS?: number; };', ], response: - "{ products?: { description: string; features: string[]; images: string[]; name: 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; }[]; }", + "{ 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; }[]; }", perLanguage: { http: { example: @@ -534,9 +534,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.aiProduct', params: ['url: string;', 'timeoutMS?: number;'], response: - "{ is_product_page?: boolean; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: { description: string; features: string[]; images: string[]; name: 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; 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; }; }", markdown: - "## ai_product\n\n`client.brand.aiProduct(url: string, timeoutMS?: number): { is_product_page?: boolean; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: object; }`\n\n**post** `/brand/ai/product`\n\nBeta feature: Given a single URL, determines if it is a product detail page, classifies the platform/product type, and extracts the product information. Supports Amazon, TikTok Shop, Etsy, and generic ecommerce sites.\n\n### Parameters\n\n- `url: string`\n The product page URL to extract product data from.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: { description: string; features: string[]; images: string[]; name: 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 - `platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'`\n - `product?: { description: string; features: string[]; images: string[]; name: 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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## ai_product\n\n`client.brand.aiProduct(url: string, timeoutMS?: number): { is_product_page?: boolean; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: object; }`\n\n**post** `/brand/ai/product`\n\nBeta feature: Given a single URL, determines if it is a product detail page, classifies the platform/product type, and extracts the product information. Supports Amazon, TikTok Shop, Etsy, and generic ecommerce sites.\n\n### Parameters\n\n- `url: string`\n The product page URL to extract product data from.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; 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 - `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 0dfb135a..c5d6d507 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -970,6 +970,14 @@ export namespace BrandAIProductResponse { */ name: string; + /** + * Stock Keeping Unit (product identifier). Extracted from structured data (JSON-LD + * Product.sku), microdata, meta tags, platform-specific identifiers (e.g. Amazon + * ASIN, Etsy listing ID), or visible SKU/Model/Item # text. Null if no identifier + * is found. + */ + sku: string | null; + /** * Tags associated with the product */ @@ -1046,6 +1054,14 @@ export namespace BrandAIProductsResponse { */ name: string; + /** + * Stock Keeping Unit (product identifier). Extracted from structured data (JSON-LD + * Product.sku), microdata, meta tags, platform-specific identifiers (e.g. Amazon + * ASIN, Etsy listing ID), or visible SKU/Model/Item # text. Null if no identifier + * is found. + */ + sku: string | null; + /** * Tags associated with the product */ From 54a32bf4e75bf1794b277eb4ce167004ad70d026 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 02:02:58 +0000 Subject: [PATCH 036/100] feat(api): api update --- .stats.yml | 4 ++-- src/resources/brand.ts | 10 ++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.stats.yml b/.stats.yml index c2c1aed7..5d1e9ce3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-a79be9698f9c8908538102f0ea3ed43ce85be94c723f81ce3f7143b6dd394c62.yml -openapi_spec_hash: 840d5e6c9fd1710942bd61ab08f7f411 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-2952aaffb14241bbdb6df2c3f4a83d21527a969cc1ed03f0ee4b3399973891a5.yml +openapi_spec_hash: ea489ac04d293ed777fefb705782e165 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/src/resources/brand.ts b/src/resources/brand.ts index c5d6d507..ca034fa2 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -971,10 +971,7 @@ export namespace BrandAIProductResponse { name: string; /** - * Stock Keeping Unit (product identifier). Extracted from structured data (JSON-LD - * Product.sku), microdata, meta tags, platform-specific identifiers (e.g. Amazon - * ASIN, Etsy listing ID), or visible SKU/Model/Item # text. Null if no identifier - * is found. + * Stock Keeping Unit (product identifier). Null if no identifier is found. */ sku: string | null; @@ -1055,10 +1052,7 @@ export namespace BrandAIProductsResponse { name: string; /** - * Stock Keeping Unit (product identifier). Extracted from structured data (JSON-LD - * Product.sku), microdata, meta tags, platform-specific identifiers (e.g. Amazon - * ASIN, Etsy listing ID), or visible SKU/Model/Item # text. Null if no identifier - * is found. + * Stock Keeping Unit (product identifier). Null if no identifier is found. */ sku: string | null; From 8b471a2874e97f1ea5e60826d57d1a26d297c357 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 25 Apr 2026 19:33:53 +0000 Subject: [PATCH 037/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5d1e9ce3..31233eaa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-2952aaffb14241bbdb6df2c3f4a83d21527a969cc1ed03f0ee4b3399973891a5.yml -openapi_spec_hash: ea489ac04d293ed777fefb705782e165 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-0556b1d48d8bff03ed38b606fdb77620a74cc8e0df9dadd3445d20a0662cea5d.yml +openapi_spec_hash: 953bc57b3ad20e8dba19cecf23ef0425 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 20c060ba3ffc59a10b22453ccaded67c87038733 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 25 Apr 2026 23:41:24 +0000 Subject: [PATCH 038/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 31233eaa..e319589f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-0556b1d48d8bff03ed38b606fdb77620a74cc8e0df9dadd3445d20a0662cea5d.yml -openapi_spec_hash: 953bc57b3ad20e8dba19cecf23ef0425 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-83beb1a8b5d19a48d62b81a81c14badd01dab69a3b636d63dc70199de3644d0d.yml +openapi_spec_hash: eeb3bbf7ccb4d14e0288cc88045dd007 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 0a31d83edb235c2b212c6d4ca1491791f5f3bd4f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 02:24:43 +0000 Subject: [PATCH 039/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 15 +++++++-------- src/resources/brand.ts | 19 +++++++------------ 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/.stats.yml b/.stats.yml index e319589f..93997187 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-83beb1a8b5d19a48d62b81a81c14badd01dab69a3b636d63dc70199de3644d0d.yml -openapi_spec_hash: eeb3bbf7ccb4d14e0288cc88045dd007 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-2c2882c6fc2b0cd3a9cc19fd1a01f969b9333a96f8bc53f83b0c3e051ddc97c4.yml +openapi_spec_hash: af01b87a25eeafec960c95f31acab235 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 44895cc3..6183a230 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -366,14 +366,13 @@ const EMBEDDED_METHODS: MethodEntry[] = [ endpoint: '/brand/prefetch', httpMethod: 'post', summary: 'Prefetch brand data for a domain', - description: - 'Signal that you may fetch brand data for a particular domain soon to improve latency. This endpoint does not charge credits and is available for paid customers to optimize future requests. [You must be on a paid plan to use this endpoint]', + description: 'Signal that you may fetch brand data for a particular domain soon to improve latency.', stainlessPath: '(resource) brand > (method) prefetch', qualified: 'client.brand.prefetch', params: ['domain: string;', 'timeoutMS?: number;'], response: '{ domain?: string; message?: string; status?: string; }', markdown: - "## prefetch\n\n`client.brand.prefetch(domain: string, timeoutMS?: number): { domain?: string; message?: string; status?: string; }`\n\n**post** `/brand/prefetch`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency. This endpoint does not charge credits and is available for paid customers to optimize future requests. [You must be on a paid plan to use this endpoint]\n\n### Parameters\n\n- `domain: string`\n Domain name to prefetch brand data for\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- `{ domain?: string; message?: string; status?: string; }`\n\n - `domain?: string`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetch({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## prefetch\n\n`client.brand.prefetch(domain: string, timeoutMS?: number): { domain?: string; message?: string; status?: string; }`\n\n**post** `/brand/prefetch`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency.\n\n### Parameters\n\n- `domain: string`\n Domain name to prefetch brand data for\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- `{ domain?: string; message?: string; status?: string; }`\n\n - `domain?: string`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetch({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -407,13 +406,13 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: 'Prefetch brand data by email', description: - "Signal that you may fetch brand data for a particular domain soon to improve latency. This endpoint accepts an email address, extracts the domain from it, validates that it's not a disposable or free email provider, and queues the domain for prefetching. This endpoint does not charge credits and is available for paid customers to optimize future requests. [You must be on a paid plan to use this endpoint]", + "Signal that you may fetch brand data for a particular domain soon to improve latency. This endpoint accepts an email address, extracts the domain from it, validates that it's not a disposable or free email provider, and queues the domain for prefetching.", stainlessPath: '(resource) brand > (method) prefetch_by_email', qualified: 'client.brand.prefetchByEmail', params: ['email: string;', 'timeoutMS?: number;'], response: '{ domain?: string; message?: string; status?: string; }', markdown: - "## prefetch_by_email\n\n`client.brand.prefetchByEmail(email: string, timeoutMS?: number): { domain?: string; message?: string; status?: string; }`\n\n**post** `/brand/prefetch-by-email`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency. This endpoint accepts an email address, extracts the domain from it, validates that it's not a disposable or free email provider, and queues the domain for prefetching. This endpoint does not charge credits and is available for paid customers to optimize future requests. [You must be on a paid plan to use this endpoint]\n\n### Parameters\n\n- `email: string`\n Email address to prefetch brand data for. The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\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- `{ domain?: string; message?: string; status?: string; }`\n\n - `domain?: string`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetchByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", + "## prefetch_by_email\n\n`client.brand.prefetchByEmail(email: string, timeoutMS?: number): { domain?: string; message?: string; status?: string; }`\n\n**post** `/brand/prefetch-by-email`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency. This endpoint accepts an email address, extracts the domain from it, validates that it's not a disposable or free email provider, and queues the domain for prefetching.\n\n### Parameters\n\n- `email: string`\n Email address to prefetch brand data for. The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\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- `{ domain?: string; message?: string; status?: string; }`\n\n - `domain?: string`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetchByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: @@ -488,7 +487,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: "Extract products from a brand's website", description: - "Beta feature: Extract product information from a brand's website. We will analyze the website and return a list of products with details such as name, description, image, pricing, features, and more.", + "Extract product information from a brand's website. We will analyze the website and return a list of products with details such as name, description, image, pricing, features, and more.", stainlessPath: '(resource) brand > (method) ai_products', qualified: 'client.brand.aiProducts', params: [ @@ -529,14 +528,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'post', summary: 'Extract a single product from a URL', description: - 'Beta feature: Given a single URL, determines if it is a product detail page, classifies the platform/product type, and extracts the product information. Supports Amazon, TikTok Shop, Etsy, and generic ecommerce sites.', + 'Given a single URL, determines if it is a product page and extracts the product information.', stainlessPath: '(resource) brand > (method) ai_product', qualified: 'client.brand.aiProduct', params: ['url: string;', 'timeoutMS?: number;'], response: "{ is_product_page?: boolean; 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; }; }", markdown: - "## ai_product\n\n`client.brand.aiProduct(url: string, timeoutMS?: number): { is_product_page?: boolean; platform?: 'amazon' | 'tiktok_shop' | 'etsy' | 'generic'; product?: object; }`\n\n**post** `/brand/ai/product`\n\nBeta feature: Given a single URL, determines if it is a product detail page, classifies the platform/product type, and extracts the product information. Supports Amazon, TikTok Shop, Etsy, and generic ecommerce sites.\n\n### Parameters\n\n- `url: string`\n The product page URL to extract product data from.\n\n- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; 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 - `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## ai_product\n\n`client.brand.aiProduct(url: string, timeoutMS?: number): { is_product_page?: boolean; 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- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; 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 - `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index ca034fa2..381dfb13 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -14,18 +14,17 @@ export class Brand extends APIResource { } /** - * Beta feature: Given a single URL, determines if it is a product detail page, - * classifies the platform/product type, and extracts the product information. - * Supports Amazon, TikTok Shop, Etsy, and generic ecommerce sites. + * Given a single URL, determines if it is a product page and extracts the product + * information. */ aiProduct(body: BrandAIProductParams, options?: RequestOptions): APIPromise { return this._client.post('/brand/ai/product', { body, ...options }); } /** - * Beta feature: Extract product information from a brand's website. We will - * analyze the website and return a list of products with details such as name, - * description, image, pricing, features, and more. + * Extract product information from a brand's website. We will analyze the website + * and return a list of products with details such as name, description, image, + * pricing, features, and more. */ aiProducts(body: BrandAIProductsParams, options?: RequestOptions): APIPromise { return this._client.post('/brand/ai/products', { body, ...options }); @@ -53,9 +52,7 @@ export class Brand extends APIResource { /** * Signal that you may fetch brand data for a particular domain soon to improve - * latency. This endpoint does not charge credits and is available for paid - * customers to optimize future requests. [You must be on a paid plan to use this - * endpoint] + * latency. */ prefetch(body: BrandPrefetchParams, options?: RequestOptions): APIPromise { return this._client.post('/brand/prefetch', { body, ...options }); @@ -65,9 +62,7 @@ export class Brand extends APIResource { * Signal that you may fetch brand data for a particular domain soon to improve * latency. This endpoint accepts an email address, extracts the domain from it, * validates that it's not a disposable or free email provider, and queues the - * domain for prefetching. This endpoint does not charge credits and is available - * for paid customers to optimize future requests. [You must be on a paid plan to - * use this endpoint] + * domain for prefetching. */ prefetchByEmail( body: BrandPrefetchByEmailParams, From 33e292c6ca0477f1cbc2f5867a60687e09c7b550 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 19:24:15 +0000 Subject: [PATCH 040/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 93997187..f6a695dd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-2c2882c6fc2b0cd3a9cc19fd1a01f969b9333a96f8bc53f83b0c3e051ddc97c4.yml -openapi_spec_hash: af01b87a25eeafec960c95f31acab235 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-e80ff2bd2c88a023bfab185593d9bbc03d81b79b46b178a724b67ffffa504fc8.yml +openapi_spec_hash: fc81cc80368feba40e621e9449f03c6a config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 9bfd24706e0432eed34a10457507498685be4160 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 23:25:39 +0000 Subject: [PATCH 041/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 6 +++--- src/resources/brand.ts | 21 ++++++++++++++++++++ tests/api-resources/brand.test.ts | 7 ++++++- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index f6a695dd..c5912706 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-e80ff2bd2c88a023bfab185593d9bbc03d81b79b46b178a724b67ffffa504fc8.yml -openapi_spec_hash: fc81cc80368feba40e621e9449f03c6a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-632b293af91698403da1bcaf3fb91259636c772e5071a2dd0fc63c42cb591307.yml +openapi_spec_hash: d03dc81f33ef92c74aa3b5dea35cdeae config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 6183a230..63a1da98 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -491,7 +491,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ stainlessPath: '(resource) brand > (method) ai_products', qualified: 'client.brand.aiProducts', params: [ - '{ domain: string; maxProducts?: number; timeoutMS?: number; } | { directUrl: string; maxProducts?: number; timeoutMS?: number; };', + '{ domain: string; maxAgeMs?: number; maxProducts?: number; timeoutMS?: number; } | { directUrl: string; maxAgeMs?: number; maxProducts?: number; timeoutMS?: number; };', ], response: "{ 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; }[]; }", @@ -531,11 +531,11 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'Given a single URL, determines if it is a product page and extracts the product information.', stainlessPath: '(resource) brand > (method) ai_product', qualified: 'client.brand.aiProduct', - params: ['url: string;', 'timeoutMS?: number;'], + params: ['url: string;', 'maxAgeMs?: number;', 'timeoutMS?: number;'], response: "{ is_product_page?: boolean; 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; }; }", markdown: - "## ai_product\n\n`client.brand.aiProduct(url: string, timeoutMS?: number): { is_product_page?: boolean; 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- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; 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 - `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## ai_product\n\n`client.brand.aiProduct(url: string, maxAgeMs?: number, timeoutMS?: number): { is_product_page?: boolean; 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- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; 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 - `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { http: { example: diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 381dfb13..01ebb43d 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -5408,6 +5408,13 @@ export interface BrandAIProductParams { */ url: string; + /** + * 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. + */ + maxAgeMs?: number; + /** * Optional timeout in milliseconds for the request. Maximum allowed value is * 300000ms (5 minutes). @@ -5424,6 +5431,13 @@ export declare namespace BrandAIProductsParams { */ domain: string; + /** + * 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. + */ + maxAgeMs?: number; + /** * Maximum number of products to extract. */ @@ -5443,6 +5457,13 @@ export declare namespace BrandAIProductsParams { */ directUrl: string; + /** + * 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. + */ + maxAgeMs?: number; + /** * Maximum number of products to extract. */ diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index e413964d..87ee675d 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -44,7 +44,11 @@ describe('resource brand', () => { // Mock server tests are disabled test.skip('aiProduct: required and optional params', async () => { - const response = await client.brand.aiProduct({ url: 'https://example.com', timeoutMS: 1000 }); + const response = await client.brand.aiProduct({ + url: 'https://example.com', + maxAgeMs: 0, + timeoutMS: 1000, + }); }); // Mock server tests are disabled @@ -63,6 +67,7 @@ describe('resource brand', () => { test.skip('aiProducts: required and optional params', async () => { const response = await client.brand.aiProducts({ domain: 'domain', + maxAgeMs: 0, maxProducts: 1, timeoutMS: 1000, }); From 31bd7717da192b95f66d9f6c2bf0639ed2857055 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 03:32:28 +0000 Subject: [PATCH 042/100] chore: restructure docs search code --- packages/mcp-server/src/local-docs-search.ts | 320 +++++++++---------- 1 file changed, 160 insertions(+), 160 deletions(-) diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 63a1da98..e9002671 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -64,29 +64,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve\n\n`client.brand.retrieve(domain: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve`\n\nRetrieve logos, backdrops, colors, industry, description, and more from any domain\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve brand data for (e.g., 'example.com', 'google.com'). Cannot be used with name or ticker parameters.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data. Works with all three lookup methods.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst brand = await client.brand.retrieve({ domain: 'domain' });\n\nconsole.log(brand);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/retrieve \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().retrieve', + typescript: { + method: 'client.brand.retrieve', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("domain")\n .build();\n BrandRetrieveResponse brand = client.brand().retrieve(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst brand = await client.brand.retrieve({ domain: 'domain' });\n\nconsole.log(brand.brand);", }, python: { method: 'brand.retrieve', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nbrand = client.brand.retrieve(\n domain="domain",\n)\nprint(brand.brand)', }, + java: { + method: 'brand().retrieve', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("domain")\n .build();\n BrandRetrieveResponse brand = client.brand().retrieve(params);\n }\n}', + }, ruby: { method: 'brand.retrieve', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nbrand = brand_dev.brand.retrieve(domain: "domain")\n\nputs(brand)', }, - typescript: { - method: 'client.brand.retrieve', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst brand = await client.brand.retrieve({ domain: 'domain' });\n\nconsole.log(brand.brand);", + 'curl https://api.brand.dev/v1/brand/retrieve \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -110,29 +110,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve_by_ticker\n\n`client.brand.retrieveByTicker(ticker: string, force_language?: string, maxSpeed?: boolean, ticker_exchange?: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-ticker`\n\nRetrieve brand information using a stock ticker symbol.\n\n### Parameters\n\n- `ticker: string`\n Stock ticker symbol to retrieve brand data for (e.g., 'AAPL', 'GOOGL', 'BRK.A'). Must be 1-15 characters, letters/numbers/dots only.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `ticker_exchange?: string`\n Optional stock exchange for the ticker. Defaults to NASDAQ if not specified.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/retrieve-by-ticker \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().retrieveByTicker', + typescript: { + method: 'client.brand.retrieveByTicker', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveByTickerParams;\nimport com.branddev.api.models.brand.BrandRetrieveByTickerResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveByTickerParams params = BrandRetrieveByTickerParams.builder()\n .ticker("ticker")\n .build();\n BrandRetrieveByTickerResponse response = client.brand().retrieveByTicker(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response.brand);", }, python: { method: 'brand.retrieve_by_ticker', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.retrieve_by_ticker(\n ticker="ticker",\n)\nprint(response.brand)', }, + java: { + method: 'brand().retrieveByTicker', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveByTickerParams;\nimport com.branddev.api.models.brand.BrandRetrieveByTickerResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveByTickerParams params = BrandRetrieveByTickerParams.builder()\n .ticker("ticker")\n .build();\n BrandRetrieveByTickerResponse response = client.brand().retrieveByTicker(params);\n }\n}', + }, ruby: { method: 'brand.retrieve_by_ticker', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.retrieve_by_ticker(ticker: "ticker")\n\nputs(response)', }, - typescript: { - method: 'client.brand.retrieveByTicker', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response.brand);", + 'curl https://api.brand.dev/v1/brand/retrieve-by-ticker \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -151,29 +151,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve_by_isin\n\n`client.brand.retrieveByIsin(isin: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-isin`\n\nRetrieve brand information using an ISIN (International Securities Identification Number). \n\n### Parameters\n\n- `isin: string`\n ISIN (International Securities Identification Number) to retrieve brand data for (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters followed by 9 alphanumeric characters and ending with a digit.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/retrieve-by-isin \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().retrieveByIsin', + typescript: { + method: 'client.brand.retrieveByIsin', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveByIsinParams;\nimport com.branddev.api.models.brand.BrandRetrieveByIsinResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveByIsinParams params = BrandRetrieveByIsinParams.builder()\n .isin("SE60513A9993")\n .build();\n BrandRetrieveByIsinResponse response = client.brand().retrieveByIsin(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response.brand);", }, python: { method: 'brand.retrieve_by_isin', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.retrieve_by_isin(\n isin="SE60513A9993",\n)\nprint(response.brand)', }, + java: { + method: 'brand().retrieveByIsin', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveByIsinParams;\nimport com.branddev.api.models.brand.BrandRetrieveByIsinResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveByIsinParams params = BrandRetrieveByIsinParams.builder()\n .isin("SE60513A9993")\n .build();\n BrandRetrieveByIsinResponse response = client.brand().retrieveByIsin(params);\n }\n}', + }, ruby: { method: 'brand.retrieve_by_isin', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.retrieve_by_isin(isin: "SE60513A9993")\n\nputs(response)', }, - typescript: { - method: 'client.brand.retrieveByIsin', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response.brand);", + 'curl https://api.brand.dev/v1/brand/retrieve-by-isin \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -197,29 +197,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve_by_name\n\n`client.brand.retrieveByName(name: string, country_gl?: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-name`\n\nRetrieve brand information using a company name.\n\n### Parameters\n\n- `name: string`\n Company name to retrieve brand data for (e.g., 'Apple Inc', 'Microsoft Corporation'). Must be 3-30 characters.\n\n- `country_gl?: string`\n Optional country code hint (GL parameter) to specify the country for the company name.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/retrieve-by-name \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().retrieveByName', + typescript: { + method: 'client.brand.retrieveByName', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveByNameParams;\nimport com.branddev.api.models.brand.BrandRetrieveByNameResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveByNameParams params = BrandRetrieveByNameParams.builder()\n .name("xxx")\n .build();\n BrandRetrieveByNameResponse response = client.brand().retrieveByName(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response.brand);", }, python: { method: 'brand.retrieve_by_name', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.retrieve_by_name(\n name="xxx",\n)\nprint(response.brand)', }, + java: { + method: 'brand().retrieveByName', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveByNameParams;\nimport com.branddev.api.models.brand.BrandRetrieveByNameResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveByNameParams params = BrandRetrieveByNameParams.builder()\n .name("xxx")\n .build();\n BrandRetrieveByNameResponse response = client.brand().retrieveByName(params);\n }\n}', + }, ruby: { method: 'brand.retrieve_by_name', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.retrieve_by_name(name: "xxx")\n\nputs(response)', }, - typescript: { - method: 'client.brand.retrieveByName', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response.brand);", + 'curl https://api.brand.dev/v1/brand/retrieve-by-name \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -238,29 +238,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve_by_email\n\n`client.brand.retrieveByEmail(email: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-email`\n\nRetrieve brand information using an email address while detecting disposable and free email addresses. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.\n\n### Parameters\n\n- `email: string`\n Email address to retrieve brand data for (e.g., 'contact@example.com'). The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/retrieve-by-email \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().retrieveByEmail', + typescript: { + method: 'client.brand.retrieveByEmail', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveByEmailParams;\nimport com.branddev.api.models.brand.BrandRetrieveByEmailResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveByEmailParams params = BrandRetrieveByEmailParams.builder()\n .email("dev@stainless.com")\n .build();\n BrandRetrieveByEmailResponse response = client.brand().retrieveByEmail(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response.brand);", }, python: { method: 'brand.retrieve_by_email', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.retrieve_by_email(\n email="dev@stainless.com",\n)\nprint(response.brand)', }, + java: { + method: 'brand().retrieveByEmail', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveByEmailParams;\nimport com.branddev.api.models.brand.BrandRetrieveByEmailResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveByEmailParams params = BrandRetrieveByEmailParams.builder()\n .email("dev@stainless.com")\n .build();\n BrandRetrieveByEmailResponse response = client.brand().retrieveByEmail(params);\n }\n}', + }, ruby: { method: 'brand.retrieve_by_email', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.retrieve_by_email(email: "dev@stainless.com")\n\nputs(response)', }, - typescript: { - method: 'client.brand.retrieveByEmail', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response.brand);", + 'curl https://api.brand.dev/v1/brand/retrieve-by-email \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -289,29 +289,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## identify_from_transaction\n\n`client.brand.identifyFromTransaction(transaction_info: string, city?: string, country_gl?: string, force_language?: string, high_confidence_only?: boolean, maxSpeed?: boolean, mcc?: string, phone?: number, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/transaction_identifier`\n\nEndpoint specially designed for platforms that want to identify transaction data by the transaction title.\n\n### Parameters\n\n- `transaction_info: string`\n Transaction information to identify the brand\n\n- `city?: string`\n Optional city name to prioritize when searching for the brand.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `high_confidence_only?: boolean`\n When set to true, the API will perform an additional verification steps to ensure the identified brand matches the transaction with high confidence.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `mcc?: string`\n Optional Merchant Category Code (MCC) to help identify the business category/industry. \n\n- `phone?: number`\n Optional phone number from the transaction to help verify brand match.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.identifyFromTransaction({ transaction_info: 'transaction_info' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/transaction_identifier \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().identifyFromTransaction', + typescript: { + method: 'client.brand.identifyFromTransaction', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandIdentifyFromTransactionParams;\nimport com.branddev.api.models.brand.BrandIdentifyFromTransactionResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandIdentifyFromTransactionParams params = BrandIdentifyFromTransactionParams.builder()\n .transactionInfo("transaction_info")\n .build();\n BrandIdentifyFromTransactionResponse response = client.brand().identifyFromTransaction(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.identifyFromTransaction({\n transaction_info: 'transaction_info',\n});\n\nconsole.log(response.brand);", }, python: { method: 'brand.identify_from_transaction', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.identify_from_transaction(\n transaction_info="transaction_info",\n)\nprint(response.brand)', }, + java: { + method: 'brand().identifyFromTransaction', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandIdentifyFromTransactionParams;\nimport com.branddev.api.models.brand.BrandIdentifyFromTransactionResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandIdentifyFromTransactionParams params = BrandIdentifyFromTransactionParams.builder()\n .transactionInfo("transaction_info")\n .build();\n BrandIdentifyFromTransactionResponse response = client.brand().identifyFromTransaction(params);\n }\n}', + }, ruby: { method: 'brand.identify_from_transaction', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.identify_from_transaction(transaction_info: "transaction_info")\n\nputs(response)', }, - typescript: { - method: 'client.brand.identifyFromTransaction', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.identifyFromTransaction({\n transaction_info: 'transaction_info',\n});\n\nconsole.log(response.brand);", + 'curl https://api.brand.dev/v1/brand/transaction_identifier \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -335,29 +335,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## ai_query\n\n`client.brand.aiQuery(data_to_extract: { datapoint_description: string; datapoint_example: string; datapoint_name: string; datapoint_type: 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url'; datapoint_list_type?: 'string' | 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url' | 'object'; datapoint_object_schema?: object; }[], domain: string, specific_pages?: { about_us?: boolean; blog?: boolean; careers?: boolean; contact_us?: boolean; faq?: boolean; home_page?: boolean; pricing?: boolean; privacy_policy?: boolean; terms_and_conditions?: boolean; }, timeoutMS?: number): { data_extracted?: object[]; domain?: string; status?: string; urls_analyzed?: string[]; }`\n\n**post** `/brand/ai/query`\n\nUse AI to extract specific data points from a brand's website. The AI will crawl the website and extract the requested information based on the provided data points.\n\n### Parameters\n\n- `data_to_extract: { datapoint_description: string; datapoint_example: string; datapoint_name: string; datapoint_type: 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url'; datapoint_list_type?: 'string' | 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url' | 'object'; datapoint_object_schema?: object; }[]`\n Array of data points to extract from the website\n\n- `domain: string`\n The domain name to analyze\n\n- `specific_pages?: { about_us?: boolean; blog?: boolean; careers?: boolean; contact_us?: boolean; faq?: boolean; home_page?: boolean; pricing?: boolean; privacy_policy?: boolean; terms_and_conditions?: boolean; }`\n Optional object specifying which pages to analyze\n - `about_us?: boolean`\n Whether to analyze the about us page\n - `blog?: boolean`\n Whether to analyze the blog\n - `careers?: boolean`\n Whether to analyze the careers page\n - `contact_us?: boolean`\n Whether to analyze the contact us page\n - `faq?: boolean`\n Whether to analyze the FAQ page\n - `home_page?: boolean`\n Whether to analyze the home page\n - `pricing?: boolean`\n Whether to analyze the pricing page\n - `privacy_policy?: boolean`\n Whether to analyze the privacy policy page\n - `terms_and_conditions?: boolean`\n Whether to analyze the terms and conditions page\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- `{ data_extracted?: { datapoint_name?: string; datapoint_value?: string | number | boolean | string[] | number[] | object[]; }[]; domain?: string; status?: string; urls_analyzed?: string[]; }`\n\n - `data_extracted?: { datapoint_name?: string; datapoint_value?: string | number | boolean | string[] | number[] | object[]; }[]`\n - `domain?: string`\n - `status?: string`\n - `urls_analyzed?: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiQuery({ data_to_extract: [{\n datapoint_description: 'datapoint_description',\n datapoint_example: 'datapoint_example',\n datapoint_name: 'datapoint_name',\n datapoint_type: 'text',\n}], domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/ai/query \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "data_to_extract": [\n {\n "datapoint_description": "datapoint_description",\n "datapoint_example": "datapoint_example",\n "datapoint_name": "datapoint_name",\n "datapoint_type": "text"\n }\n ],\n "domain": "domain"\n }\'', - }, - java: { - method: 'brand().aiQuery', + typescript: { + method: 'client.brand.aiQuery', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\nimport com.branddev.api.models.brand.BrandAiQueryResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandAiQueryParams params = BrandAiQueryParams.builder()\n .addDataToExtract(BrandAiQueryParams.DataToExtract.builder()\n .datapointDescription("datapoint_description")\n .datapointExample("datapoint_example")\n .datapointName("datapoint_name")\n .datapointType(BrandAiQueryParams.DataToExtract.DatapointType.TEXT)\n .build())\n .domain("domain")\n .build();\n BrandAiQueryResponse response = client.brand().aiQuery(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.aiQuery({\n data_to_extract: [\n {\n datapoint_description: 'datapoint_description',\n datapoint_example: 'datapoint_example',\n datapoint_name: 'datapoint_name',\n datapoint_type: 'text',\n },\n ],\n domain: 'domain',\n});\n\nconsole.log(response.data_extracted);", }, python: { method: 'brand.ai_query', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.ai_query(\n data_to_extract=[{\n "datapoint_description": "datapoint_description",\n "datapoint_example": "datapoint_example",\n "datapoint_name": "datapoint_name",\n "datapoint_type": "text",\n }],\n domain="domain",\n)\nprint(response.data_extracted)', }, + java: { + method: 'brand().aiQuery', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\nimport com.branddev.api.models.brand.BrandAiQueryResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandAiQueryParams params = BrandAiQueryParams.builder()\n .addDataToExtract(BrandAiQueryParams.DataToExtract.builder()\n .datapointDescription("datapoint_description")\n .datapointExample("datapoint_example")\n .datapointName("datapoint_name")\n .datapointType(BrandAiQueryParams.DataToExtract.DatapointType.TEXT)\n .build())\n .domain("domain")\n .build();\n BrandAiQueryResponse response = client.brand().aiQuery(params);\n }\n}', + }, ruby: { method: 'brand.ai_query', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.ai_query(\n data_to_extract: [\n {\n datapoint_description: "datapoint_description",\n datapoint_example: "datapoint_example",\n datapoint_name: "datapoint_name",\n datapoint_type: :text\n }\n ],\n domain: "domain"\n)\n\nputs(response)', }, - typescript: { - method: 'client.brand.aiQuery', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.aiQuery({\n data_to_extract: [\n {\n datapoint_description: 'datapoint_description',\n datapoint_example: 'datapoint_example',\n datapoint_name: 'datapoint_name',\n datapoint_type: 'text',\n },\n ],\n domain: 'domain',\n});\n\nconsole.log(response.data_extracted);", + 'curl https://api.brand.dev/v1/brand/ai/query \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "data_to_extract": [\n {\n "datapoint_description": "datapoint_description",\n "datapoint_example": "datapoint_example",\n "datapoint_name": "datapoint_name",\n "datapoint_type": "text"\n }\n ],\n "domain": "domain"\n }\'', }, }, }, @@ -374,29 +374,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## prefetch\n\n`client.brand.prefetch(domain: string, timeoutMS?: number): { domain?: string; message?: string; status?: string; }`\n\n**post** `/brand/prefetch`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency.\n\n### Parameters\n\n- `domain: string`\n Domain name to prefetch brand data for\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- `{ domain?: string; message?: string; status?: string; }`\n\n - `domain?: string`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetch({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/prefetch \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "domain": "domain"\n }\'', - }, - java: { - method: 'brand().prefetch', + typescript: { + method: 'client.brand.prefetch', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandPrefetchParams;\nimport com.branddev.api.models.brand.BrandPrefetchResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandPrefetchParams params = BrandPrefetchParams.builder()\n .domain("domain")\n .build();\n BrandPrefetchResponse response = client.brand().prefetch(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.prefetch({ domain: 'domain' });\n\nconsole.log(response.domain);", }, python: { method: 'brand.prefetch', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.prefetch(\n domain="domain",\n)\nprint(response.domain)', }, + java: { + method: 'brand().prefetch', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandPrefetchParams;\nimport com.branddev.api.models.brand.BrandPrefetchResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandPrefetchParams params = BrandPrefetchParams.builder()\n .domain("domain")\n .build();\n BrandPrefetchResponse response = client.brand().prefetch(params);\n }\n}', + }, ruby: { method: 'brand.prefetch', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.prefetch(domain: "domain")\n\nputs(response)', }, - typescript: { - method: 'client.brand.prefetch', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.prefetch({ domain: 'domain' });\n\nconsole.log(response.domain);", + 'curl https://api.brand.dev/v1/brand/prefetch \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "domain": "domain"\n }\'', }, }, }, @@ -414,29 +414,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## prefetch_by_email\n\n`client.brand.prefetchByEmail(email: string, timeoutMS?: number): { domain?: string; message?: string; status?: string; }`\n\n**post** `/brand/prefetch-by-email`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency. This endpoint accepts an email address, extracts the domain from it, validates that it's not a disposable or free email provider, and queues the domain for prefetching.\n\n### Parameters\n\n- `email: string`\n Email address to prefetch brand data for. The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\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- `{ domain?: string; message?: string; status?: string; }`\n\n - `domain?: string`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetchByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/prefetch-by-email \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "email": "dev@stainless.com"\n }\'', - }, - java: { - method: 'brand().prefetchByEmail', + typescript: { + method: 'client.brand.prefetchByEmail', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandPrefetchByEmailParams;\nimport com.branddev.api.models.brand.BrandPrefetchByEmailResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandPrefetchByEmailParams params = BrandPrefetchByEmailParams.builder()\n .email("dev@stainless.com")\n .build();\n BrandPrefetchByEmailResponse response = client.brand().prefetchByEmail(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.prefetchByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response.domain);", }, python: { method: 'brand.prefetch_by_email', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.prefetch_by_email(\n email="dev@stainless.com",\n)\nprint(response.domain)', }, + java: { + method: 'brand().prefetchByEmail', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandPrefetchByEmailParams;\nimport com.branddev.api.models.brand.BrandPrefetchByEmailResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandPrefetchByEmailParams params = BrandPrefetchByEmailParams.builder()\n .email("dev@stainless.com")\n .build();\n BrandPrefetchByEmailResponse response = client.brand().prefetchByEmail(params);\n }\n}', + }, ruby: { method: 'brand.prefetch_by_email', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.prefetch_by_email(email: "dev@stainless.com")\n\nputs(response)', }, - typescript: { - method: 'client.brand.prefetchByEmail', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.prefetchByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response.domain);", + 'curl https://api.brand.dev/v1/brand/prefetch-by-email \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "email": "dev@stainless.com"\n }\'', }, }, }, @@ -455,29 +455,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve_simplified\n\n`client.brand.retrieveSimplified(domain: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-simplified`\n\nReturns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. Optimized for faster responses and reduced data transfer.\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve simplified brand data for\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- `{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveSimplified({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/retrieve-simplified \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().retrieveSimplified', + typescript: { + method: 'client.brand.retrieveSimplified', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveSimplifiedParams;\nimport com.branddev.api.models.brand.BrandRetrieveSimplifiedResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveSimplifiedParams params = BrandRetrieveSimplifiedParams.builder()\n .domain("domain")\n .build();\n BrandRetrieveSimplifiedResponse response = client.brand().retrieveSimplified(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveSimplified({ domain: 'domain' });\n\nconsole.log(response.brand);", }, python: { method: 'brand.retrieve_simplified', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.retrieve_simplified(\n domain="domain",\n)\nprint(response.brand)', }, + java: { + method: 'brand().retrieveSimplified', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveSimplifiedParams;\nimport com.branddev.api.models.brand.BrandRetrieveSimplifiedResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandRetrieveSimplifiedParams params = BrandRetrieveSimplifiedParams.builder()\n .domain("domain")\n .build();\n BrandRetrieveSimplifiedResponse response = client.brand().retrieveSimplified(params);\n }\n}', + }, ruby: { method: 'brand.retrieve_simplified', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.retrieve_simplified(domain: "domain")\n\nputs(response)', }, - typescript: { - method: 'client.brand.retrieveSimplified', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.retrieveSimplified({ domain: 'domain' });\n\nconsole.log(response.brand);", + 'curl https://api.brand.dev/v1/brand/retrieve-simplified \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -496,29 +496,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ 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; }[]; }", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/ai/products \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "domain": "domain"\n }\'', - }, - java: { - method: 'brand().aiProducts', + typescript: { + method: 'client.brand.aiProducts', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandAiProductsParams;\nimport com.branddev.api.models.brand.BrandAiProductsResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandAiProductsParams.Body.ByDomain params = BrandAiProductsParams.Body.ByDomain.builder()\n .domain("domain")\n .build();\n BrandAiProductsResponse response = client.brand().aiProducts(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.aiProducts({ domain: 'domain' });\n\nconsole.log(response.products);", }, python: { method: 'brand.ai_products', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.ai_products(\n domain="domain",\n)\nprint(response.products)', }, + java: { + method: 'brand().aiProducts', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandAiProductsParams;\nimport com.branddev.api.models.brand.BrandAiProductsResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandAiProductsParams.Body.ByDomain params = BrandAiProductsParams.Body.ByDomain.builder()\n .domain("domain")\n .build();\n BrandAiProductsResponse response = client.brand().aiProducts(params);\n }\n}', + }, ruby: { method: 'brand.ai_products', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.ai_products(body: {domain: "domain"})\n\nputs(response)', }, - typescript: { - method: 'client.brand.aiProducts', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.aiProducts({ domain: 'domain' });\n\nconsole.log(response.products);", + 'curl https://api.brand.dev/v1/brand/ai/products \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "domain": "domain"\n }\'', }, }, }, @@ -537,29 +537,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## ai_product\n\n`client.brand.aiProduct(url: string, maxAgeMs?: number, timeoutMS?: number): { is_product_page?: boolean; 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- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; 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 - `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/brand/ai/product \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "url": "https://example.com"\n }\'', - }, - java: { - method: 'brand().aiProduct', + typescript: { + method: 'client.brand.aiProduct', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandAiProductParams;\nimport com.branddev.api.models.brand.BrandAiProductResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandAiProductParams params = BrandAiProductParams.builder()\n .url("https://example.com")\n .build();\n BrandAiProductResponse response = client.brand().aiProduct(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response.is_product_page);", }, python: { method: 'brand.ai_product', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.ai_product(\n url="https://example.com",\n)\nprint(response.is_product_page)', }, + java: { + method: 'brand().aiProduct', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandAiProductParams;\nimport com.branddev.api.models.brand.BrandAiProductResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandAiProductParams params = BrandAiProductParams.builder()\n .url("https://example.com")\n .build();\n BrandAiProductResponse response = client.brand().aiProduct(params);\n }\n}', + }, ruby: { method: 'brand.ai_product', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.ai_product(url: "https://example.com")\n\nputs(response)', }, - typescript: { - method: 'client.brand.aiProduct', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response.is_product_page);", + 'curl https://api.brand.dev/v1/brand/ai/product \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY" \\\n -d \'{\n "url": "https://example.com"\n }\'', }, }, }, @@ -576,29 +576,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, maxAgeMs?: number, parsePDF?: boolean): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and returned wrapped in . When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/web/scrape/html \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().webScrapeHtml', + typescript: { + method: 'client.brand.webScrapeHTML', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandWebScrapeHtmlParams;\nimport com.branddev.api.models.brand.BrandWebScrapeHtmlResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandWebScrapeHtmlParams params = BrandWebScrapeHtmlParams.builder()\n .url("https://example.com")\n .build();\n BrandWebScrapeHtmlResponse response = client.brand().webScrapeHtml(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response.html);", }, python: { method: 'brand.web_scrape_html', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.web_scrape_html(\n url="https://example.com",\n)\nprint(response.html)', }, + java: { + method: 'brand().webScrapeHtml', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandWebScrapeHtmlParams;\nimport com.branddev.api.models.brand.BrandWebScrapeHtmlResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandWebScrapeHtmlParams params = BrandWebScrapeHtmlParams.builder()\n .url("https://example.com")\n .build();\n BrandWebScrapeHtmlResponse response = client.brand().webScrapeHtml(params);\n }\n}', + }, ruby: { method: 'brand.web_scrape_html', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.web_scrape_html(url: "https://example.com")\n\nputs(response)', }, - typescript: { - method: 'client.brand.webScrapeHTML', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response.html);", + 'curl https://api.brand.dev/v1/web/scrape/html \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -623,29 +623,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, parsePDF?: boolean, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and converted to Markdown. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/web/scrape/markdown \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().webScrapeMd', + typescript: { + method: 'client.brand.webScrapeMd', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandWebScrapeMdParams;\nimport com.branddev.api.models.brand.BrandWebScrapeMdResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandWebScrapeMdParams params = BrandWebScrapeMdParams.builder()\n .url("https://example.com")\n .build();\n BrandWebScrapeMdResponse response = client.brand().webScrapeMd(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response.markdown);", }, python: { method: 'brand.web_scrape_md', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.web_scrape_md(\n url="https://example.com",\n)\nprint(response.markdown)', }, + java: { + method: 'brand().webScrapeMd', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandWebScrapeMdParams;\nimport com.branddev.api.models.brand.BrandWebScrapeMdResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandWebScrapeMdParams params = BrandWebScrapeMdParams.builder()\n .url("https://example.com")\n .build();\n BrandWebScrapeMdResponse response = client.brand().webScrapeMd(params);\n }\n}', + }, ruby: { method: 'brand.web_scrape_md', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.web_scrape_md(url: "https://example.com")\n\nputs(response)', }, - typescript: { - method: 'client.brand.webScrapeMd', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response.markdown);", + 'curl https://api.brand.dev/v1/web/scrape/markdown \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -664,29 +664,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nScrapes all images from the given URL. Extracts images from img, svg, picture/source, link, and video elements including inline SVGs, base64 data URIs, and standard URLs.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape images from (must include http:// or https:// protocol)\n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/web/scrape/images \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().webScrapeImages', + typescript: { + method: 'client.brand.webScrapeImages', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandWebScrapeImagesParams;\nimport com.branddev.api.models.brand.BrandWebScrapeImagesResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandWebScrapeImagesParams params = BrandWebScrapeImagesParams.builder()\n .url("https://example.com")\n .build();\n BrandWebScrapeImagesResponse response = client.brand().webScrapeImages(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response.images);", }, python: { method: 'brand.web_scrape_images', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.web_scrape_images(\n url="https://example.com",\n)\nprint(response.images)', }, + java: { + method: 'brand().webScrapeImages', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandWebScrapeImagesParams;\nimport com.branddev.api.models.brand.BrandWebScrapeImagesResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandWebScrapeImagesParams params = BrandWebScrapeImagesParams.builder()\n .url("https://example.com")\n .build();\n BrandWebScrapeImagesResponse response = client.brand().webScrapeImages(params);\n }\n}', + }, ruby: { method: 'brand.web_scrape_images', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.web_scrape_images(url: "https://example.com")\n\nputs(response)', }, - typescript: { - method: 'client.brand.webScrapeImages', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response.images);", + 'curl https://api.brand.dev/v1/web/scrape/images \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, @@ -704,29 +704,29 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number, urlRegex?: string): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\n\n- `urlRegex?: string`\n Optional RE2-compatible regex pattern. Only URLs matching this pattern are returned and counted against maxLinks.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { - http: { - example: - 'curl https://api.brand.dev/v1/web/scrape/sitemap \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', - }, - java: { - method: 'brand().webScrapeSitemap', + typescript: { + method: 'client.brand.webScrapeSitemap', example: - 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandWebScrapeSitemapParams;\nimport com.branddev.api.models.brand.BrandWebScrapeSitemapResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandWebScrapeSitemapParams params = BrandWebScrapeSitemapParams.builder()\n .domain("domain")\n .build();\n BrandWebScrapeSitemapResponse response = client.brand().webScrapeSitemap(params);\n }\n}', + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response.domain);", }, python: { method: 'brand.web_scrape_sitemap', example: 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.web_scrape_sitemap(\n domain="domain",\n)\nprint(response.domain)', }, + java: { + method: 'brand().webScrapeSitemap', + example: + 'package com.branddev.api.example;\n\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandWebScrapeSitemapParams;\nimport com.branddev.api.models.brand.BrandWebScrapeSitemapResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\n BrandWebScrapeSitemapParams params = BrandWebScrapeSitemapParams.builder()\n .domain("domain")\n .build();\n BrandWebScrapeSitemapResponse response = client.brand().webScrapeSitemap(params);\n }\n}', + }, ruby: { method: 'brand.web_scrape_sitemap', example: 'require "brand_dev"\n\nbrand_dev = BrandDev::Client.new(api_key: "My API Key")\n\nresponse = brand_dev.brand.web_scrape_sitemap(domain: "domain")\n\nputs(response)', }, - typescript: { - method: 'client.brand.webScrapeSitemap', + http: { example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response.domain);", + 'curl https://api.brand.dev/v1/web/scrape/sitemap \\\n -H "Authorization: Bearer $BRAND_DEV_API_KEY"', }, }, }, From 1b4fdd639c77e493c053113dafff49b70dfec8ca Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 03:38:05 +0000 Subject: [PATCH 043/100] chore(internal): codegen related update --- scripts/utils/postprocess-files.cjs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/utils/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs index deae575e..a8cdeb7c 100644 --- a/scripts/utils/postprocess-files.cjs +++ b/scripts/utils/postprocess-files.cjs @@ -23,12 +23,19 @@ async function postprocess() { // strip out lib="dom", types="node", and types="react" references; these // are needed at build time, but would pollute the user's TS environment - const transformed = code.replace( + let transformed = code.replace( /^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n', ); + // TypeScript's declaration emitter collapses /** @ts-ignore */ onto the same + // line as the type declaration, which doesn't work. So we convert to // @ts-ignore + // on its own line to properly suppresses errors. + if (file.endsWith('.d.ts') || file.endsWith('.d.mts') || file.endsWith('.d.cts')) { + transformed = transformed.replace(/\/\*\* @ts-ignore\b[^*]*\*\/ /gm, '// @ts-ignore\n'); + } + if (transformed !== code) { console.error(`wrote ${path.relative(process.cwd(), file)}`); await fs.promises.writeFile(file, transformed, 'utf8'); From bdd9f4689b6a90bff41264325dbead0397f92aed Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 03:38:50 +0000 Subject: [PATCH 044/100] feat: support setting headers via env --- src/client.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/client.ts b/src/client.ts index 9af23453..82ea7b3d 100644 --- a/src/client.ts +++ b/src/client.ts @@ -202,6 +202,18 @@ export class BrandDev { this.fetch = options.fetch ?? Shims.getDefaultFetch(); this.#encoder = Opts.FallbackEncoder; + const customHeadersEnv = readEnv('BRAND_DEV_CUSTOM_HEADERS'); + if (customHeadersEnv) { + const parsed: Record = {}; + for (const line of customHeadersEnv.split('\n')) { + const colon = line.indexOf(':'); + if (colon >= 0) { + parsed[line.substring(0, colon).trim()] = line.substring(colon + 1).trim(); + } + } + options.defaultHeaders = { ...parsed, ...options.defaultHeaders }; + } + this._options = options; this.apiKey = apiKey; From cf9b19f49aa1c18f6054e89f6fe0005db34b1e93 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 05:15:59 +0000 Subject: [PATCH 045/100] chore(format): run eslint and prettier separately --- .github/workflows/release-doctor.yml | 1 - eslint.config.mjs | 3 --- package.json | 1 - scripts/fast-format | 9 +++----- scripts/format | 3 +-- scripts/lint | 3 +++ src/internal/types.ts | 14 ++++++------ yarn.lock | 32 ---------------------------- 8 files changed, 13 insertions(+), 53 deletions(-) diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 42ed9a00..0c860c4a 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -17,4 +17,3 @@ jobs: - name: Check release environment run: | bash ./bin/check-release-environment - diff --git a/eslint.config.mjs b/eslint.config.mjs index 41a735ec..e643b3d3 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,7 +1,6 @@ // @ts-check import tseslint from 'typescript-eslint'; import unusedImports from 'eslint-plugin-unused-imports'; -import prettier from 'eslint-plugin-prettier'; export default tseslint.config( { @@ -14,11 +13,9 @@ export default tseslint.config( plugins: { '@typescript-eslint': tseslint.plugin, 'unused-imports': unusedImports, - prettier, }, rules: { 'no-unused-vars': 'off', - 'prettier/prettier': 'error', 'unused-imports/no-unused-imports': 'error', 'no-restricted-imports': [ 'error', diff --git a/package.json b/package.json index 245c867b..22c619e3 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", "eslint": "^9.39.1", - "eslint-plugin-prettier": "^5.4.1", "eslint-plugin-unused-imports": "^4.1.4", "iconv-lite": "^0.6.3", "jest": "^29.4.0", diff --git a/scripts/fast-format b/scripts/fast-format index 53721ac0..f1873aef 100755 --- a/scripts/fast-format +++ b/scripts/fast-format @@ -31,10 +31,7 @@ if ! [ -z "$ESLINT_FILES" ]; then fi echo "==> Running prettier --write" -# format things eslint didn't -PRETTIER_FILES="$(grep '\.\(js\|json\)$' "$FILE_LIST" || true)" -if ! [ -z "$PRETTIER_FILES" ]; then - echo "$PRETTIER_FILES" | xargs ./node_modules/.bin/prettier \ - --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern \ - '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +if ! [ -z "$FILE_LIST" ]; then + cat "$FILE_LIST" | xargs ./node_modules/.bin/prettier \ + --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern --ignore-unknown fi diff --git a/scripts/format b/scripts/format index 7a756401..b1b2c17a 100755 --- a/scripts/format +++ b/scripts/format @@ -8,5 +8,4 @@ echo "==> Running eslint --fix" ./node_modules/.bin/eslint --fix . echo "==> Running prettier --write" -# format things eslint didn't -./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +./node_modules/.bin/prettier --write --cache --cache-strategy metadata . diff --git a/scripts/lint b/scripts/lint index 3ffb78a6..1f532548 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,6 +4,9 @@ set -e cd "$(dirname "$0")/.." +echo "==> Running prettier --check" +./node_modules/.bin/prettier --check . + echo "==> Running eslint" ./node_modules/.bin/eslint . diff --git a/src/internal/types.ts b/src/internal/types.ts index b668dfc0..a050513a 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -40,7 +40,6 @@ type OverloadedParameters = : T extends (...args: infer A) => unknown ? A : never; -/* eslint-disable */ /** * These imports attempt to get types from a parent package's dependencies. * Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which @@ -63,19 +62,18 @@ type OverloadedParameters = * * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition */ -/** @ts-ignore For users with \@types/node */ +/** @ts-ignore For users with \@types/node */ /* prettier-ignore */ type UndiciTypesRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with undici */ +/** @ts-ignore For users with undici */ /* prettier-ignore */ type UndiciRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with \@types/bun */ +/** @ts-ignore For users with \@types/bun */ /* prettier-ignore */ type BunRequestInit = globalThis.FetchRequestInit; -/** @ts-ignore For users with node-fetch@2 */ +/** @ts-ignore For users with node-fetch@2 */ /* prettier-ignore */ type NodeFetch2RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ +/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ /* prettier-ignore */ type NodeFetch3RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users who use Deno */ +/** @ts-ignore For users who use Deno */ /* prettier-ignore */ type FetchRequestInit = NonNullable[1]>; -/* eslint-enable */ type RequestInits = | NotAny diff --git a/yarn.lock b/yarn.lock index f6eae3cd..18e7cbdc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -709,11 +709,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pkgr/core@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" - integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== - "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -1515,14 +1510,6 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-plugin-prettier@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz#99b55d7dd70047886b2222fdd853665f180b36af" - integrity sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg== - dependencies: - prettier-linter-helpers "^1.0.0" - synckit "^0.11.7" - eslint-plugin-unused-imports@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738" @@ -1674,11 +1661,6 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== - fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" @@ -2841,13 +2823,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - prettier@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848" @@ -3144,13 +3119,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.11.7: - version "0.11.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457" - integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A== - dependencies: - "@pkgr/core" "^0.2.4" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" From d9e9e3eb316825a053b4443977927b5589f47008 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 05:44:40 +0000 Subject: [PATCH 046/100] chore: avoid formatting file that gets changed during releases --- .prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierignore b/.prettierignore index 7cc13dd1..36afd3b3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,6 +2,7 @@ CHANGELOG.md /ecosystem-tests/*/** /node_modules /deno +/packages/mcp-server/manifest.json # don't format tsc output, will break source maps dist From ab21d386489cecfb7c62aaa6347faaa04855007d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 05:45:34 +0000 Subject: [PATCH 047/100] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index c5912706..725fb756 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-632b293af91698403da1bcaf3fb91259636c772e5071a2dd0fc63c42cb591307.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-632b293af91698403da1bcaf3fb91259636c772e5071a2dd0fc63c42cb591307.yml openapi_spec_hash: d03dc81f33ef92c74aa3b5dea35cdeae config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 8186ca9abf8c3dc0f1287135dd43743305c11fa8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 04:29:17 +0000 Subject: [PATCH 048/100] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 725fb756..a6057b75 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-632b293af91698403da1bcaf3fb91259636c772e5071a2dd0fc63c42cb591307.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-c651aa591ed6b1a64ece1e0e6336b2d11daed5ed258bd511edcbec96d9567d1b.yml openapi_spec_hash: d03dc81f33ef92c74aa3b5dea35cdeae config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 13ea0d141a1d859ec241e5b79b852d46bd633fd9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 15:01:06 +0000 Subject: [PATCH 049/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 7 ++++--- src/resources/brand.ts | 10 ++++++++++ tests/api-resources/brand.test.ts | 2 ++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index a6057b75..6eedefc5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-c651aa591ed6b1a64ece1e0e6336b2d11daed5ed258bd511edcbec96d9567d1b.yml -openapi_spec_hash: d03dc81f33ef92c74aa3b5dea35cdeae +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-ca091b4b323baadb654b7292374b8712b6de260f3c1f8f0944caf20795f608ad.yml +openapi_spec_hash: 2bc6f537bfa055541621423722ea85f2 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index e9002671..c146c293 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -571,10 +571,10 @@ const EMBEDDED_METHODS: MethodEntry[] = [ description: 'Scrapes the given URL and returns the raw HTML content of the page.', stainlessPath: '(resource) brand > (method) web_scrape_html', qualified: 'client.brand.webScrapeHTML', - params: ['url: string;', 'maxAgeMs?: number;', 'parsePDF?: boolean;'], + params: ['url: string;', 'includeFrames?: boolean;', 'maxAgeMs?: number;', 'parsePDF?: boolean;'], response: '{ html: string; success: true; url: string; }', markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, maxAgeMs?: number, parsePDF?: boolean): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and returned wrapped in . When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, includeFrames?: boolean, maxAgeMs?: number, parsePDF?: boolean): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and returned wrapped in . When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', @@ -612,6 +612,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.webScrapeMd', params: [ 'url: string;', + 'includeFrames?: boolean;', 'includeImages?: boolean;', 'includeLinks?: boolean;', 'maxAgeMs?: number;', @@ -621,7 +622,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ ], response: '{ markdown: string; success: true; url: string; }', markdown: - "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, parsePDF?: boolean, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and converted to Markdown. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, parsePDF?: boolean, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and converted to Markdown. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeMd', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 01ebb43d..2a1a132c 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -6962,6 +6962,11 @@ export interface BrandWebScrapeHTMLParams { */ url: string; + /** + * When true, iframes are rendered inline into the returned HTML. + */ + includeFrames?: boolean; + /** * 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 @@ -6991,6 +6996,11 @@ export interface BrandWebScrapeMdParams { */ url: string; + /** + * When true, the contents of iframes are rendered to Markdown. + */ + includeFrames?: boolean; + /** * Include image references in Markdown output */ diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 87ee675d..c76b098c 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -308,6 +308,7 @@ describe('resource brand', () => { test.skip('webScrapeHTML: required and optional params', async () => { const response = await client.brand.webScrapeHTML({ url: 'https://example.com', + includeFrames: true, maxAgeMs: 0, parsePDF: true, }); @@ -346,6 +347,7 @@ describe('resource brand', () => { test.skip('webScrapeMd: required and optional params', async () => { const response = await client.brand.webScrapeMd({ url: 'https://example.com', + includeFrames: true, includeImages: true, includeLinks: true, maxAgeMs: 0, From 4d3fdb6229a1508075ce688f4e918e72608be993 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 May 2026 05:07:40 +0000 Subject: [PATCH 050/100] docs: clarify forwards compat behavior --- packages/mcp-server/src/local-docs-search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index c146c293..2819f902 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -737,7 +737,7 @@ const EMBEDDED_READMES: { language: string; content: string }[] = [ { language: 'java', content: - '# Brand Dev Java API Library\n\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.0.1)\n[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1)\n\n\nThe Brand Dev Java SDK provides convenient access to the [Brand Dev REST API](https://docs.context.dev/) from applications written in Java.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1).\n\n\n\n## Installation\n\n\n\n### Gradle\n\n~~~kotlin\nimplementation("com.branddev.api:brand-dev-java:0.0.1")\n~~~\n\n### Maven\n\n~~~xml\n\n com.branddev.api\n brand-dev-java\n 0.0.1\n\n~~~\n\n\n\n## Requirements\n\nThis library requires Java 8 or later.\n\n## Usage\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nBrandRetrieveResponse brand = client.brand().retrieve(params);\n```\n\n## Client configuration\n\nConfigure the client using system properties or environment variables:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n```\n\nOr manually:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .apiKey("My API Key")\n .build();\n```\n\nOr using a combination of the two approaches:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n // Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n // Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\n .fromEnv()\n .apiKey("My API Key")\n .build();\n```\n\nSee this table for the available options:\n\n| Setter | System property | Environment variable | Required | Default value |\n| --------- | ------------------ | -------------------- | -------- | ---------------------------- |\n| `apiKey` | `branddev.apiKey` | `BRAND_DEV_API_KEY` | true | - |\n| `baseUrl` | `branddev.baseUrl` | `BRAND_DEV_BASE_URL` | true | `"https://api.brand.dev/v1"` |\n\nSystem properties take precedence over environment variables.\n\n> [!TIP]\n> Don\'t create more than one client in the same application. Each client has a connection pool and\n> thread pools, which are more efficient to share between requests.\n\n### Modifying configuration\n\nTo temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\n\nBrandDevClient clientWithOptions = client.withOptions(optionsBuilder -> {\n optionsBuilder.baseUrl("https://example.com");\n optionsBuilder.maxRetries(42);\n});\n```\n\nThe `withOptions()` method does not affect the original client or service.\n\n## Requests and responses\n\nTo send a request to the Brand Dev API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.\n\nFor example, `client.brand().retrieve(...)` should be called with an instance of `BrandRetrieveParams`, and it will return an instance of `BrandRetrieveResponse`.\n\n## Immutability\n\nEach class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.\n\nEach class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.\n\nBecause each class is immutable, builder modification will _never_ affect already built class instances.\n\n## Asynchronous execution\n\nThe default client is synchronous. To switch to asynchronous execution, call the `async()` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.async().brand().retrieve(params);\n```\n\nOr create an asynchronous client from the beginning:\n\n```java\nimport com.branddev.api.client.BrandDevClientAsync;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClientAsync;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClientAsync client = BrandDevOkHttpClientAsync.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.brand().retrieve(params);\n```\n\nThe asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.\n\n\n\n\n\n\n\n## Raw responses\n\nThe SDK defines methods that deserialize responses into instances of Java classes. However, these methods don\'t provide access to the response headers, status code, or the raw response body.\n\nTo access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:\n\n```java\nimport com.branddev.api.core.http.Headers;\nimport com.branddev.api.core.http.HttpResponseFor;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nHttpResponseFor brand = client.brand().withRawResponse().retrieve(params);\n\nint statusCode = brand.statusCode();\nHeaders headers = brand.headers();\n```\n\nYou can still deserialize the response into an instance of a Java class if needed:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse parsedBrand = brand.parse();\n```\n\n## Error handling\n\nThe SDK throws custom unchecked exception types:\n\n- [`BrandDevServiceException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:\n\n | Status | Exception |\n | ------ | -------------------------------------------------- |\n | 400 | [`BadRequestException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BadRequestException.kt) |\n | 401 | [`UnauthorizedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnauthorizedException.kt) |\n | 403 | [`PermissionDeniedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/PermissionDeniedException.kt) |\n | 404 | [`NotFoundException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/NotFoundException.kt) |\n | 422 | [`UnprocessableEntityException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnprocessableEntityException.kt) |\n | 429 | [`RateLimitException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/RateLimitException.kt) |\n | 5xx | [`InternalServerException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/InternalServerException.kt) |\n | others | [`UnexpectedStatusCodeException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnexpectedStatusCodeException.kt) |\n\n- [`BrandDevIoException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevIoException.kt): I/O networking errors.\n\n- [`BrandDevRetryableException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevRetryableException.kt): Generic error indicating a failure that could be retried by the client.\n\n- [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that\'s supposed to be required, but the API unexpectedly omitted it from the response.\n\n- [`BrandDevException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.\n\n\n\n## Logging\n\nThe SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).\n\nEnable logging by setting the `BRAND_DEV_LOG` environment variable to `info`:\n\n```sh\nexport BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging:\n\n```sh\nexport BRAND_DEV_LOG=debug\n```\n\n## ProGuard and R8\n\nAlthough the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `brand-dev-java-core` is published with a [configuration file](brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).\n\nProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.\n\n\n\n\n\n## Jackson\n\nThe SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.\n\nThe SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).\n\nIf the SDK threw an exception, but you\'re _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt).\n\n> [!CAUTION]\n> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.\n\nAlso note that there are bugs in older Jackson versions that can affect the SDK. We don\'t work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead.\n\n## Network options\n\n### Retries\n\nThe SDK automatically retries 2 times by default, with a short exponential backoff between requests.\n\nOnly the following error types are retried:\n- Connection errors (for example, due to a network connectivity problem)\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- 5xx Internal\n\nThe API may also explicitly instruct the SDK to retry or not retry a request.\n\nTo set a custom number of retries, configure the client using the `maxRetries` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .maxRetries(4)\n .build();\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default.\n\nTo set a custom timeout, configure the method call using the `timeout` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .timeout(Duration.ofSeconds(30))\n .build();\n```\n\n### Proxies\n\nTo route requests through a proxy, configure the client using the `proxy` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(new Proxy(\n Proxy.Type.HTTP, new InetSocketAddress(\n "https://example.com", 8080\n )\n ))\n .build();\n```\n\n### Connection pooling\n\nTo customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.\n .maxIdleConnections(10)\n .keepAliveDuration(Duration.ofMinutes(2))\n .build();\n```\n\nIf both options are unset, OkHttp\'s default connection pool settings are used.\n\n### HTTPS\n\n> [!NOTE]\n> Most applications should not call these methods, and instead use the system defaults. The defaults include\n> special optimizations that can be lost if the implementations are modified.\n\nTo configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.\n .sslSocketFactory(yourSSLSocketFactory)\n .trustManager(yourTrustManager)\n .hostnameVerifier(yourHostnameVerifier)\n .build();\n```\n\n\n\n### Custom HTTP client\n\nThe SDK consists of three artifacts:\n- `brand-dev-java-core`\n - Contains core SDK logic\n - Does not depend on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClient.kt), [`BrandDevClientAsync`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsync.kt), [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt), and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), all of which can work with any HTTP client\n- `brand-dev-java-client-okhttp`\n - Depends on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) and [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), which provide a way to construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), respectively, using OkHttp\n- `brand-dev-java`\n - Depends on and exposes the APIs of both `brand-dev-java-core` and `brand-dev-java-client-okhttp`\n - Does not have its own logic\n\nThis structure allows replacing the SDK\'s default HTTP client without pulling in unnecessary dependencies.\n\n#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)\n\n> [!TIP]\n> Try the available [network options](#network-options) before replacing the default client.\n\nTo use a customized `OkHttpClient`:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Copy `brand-dev-java-client-okhttp`\'s [`OkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/OkHttpClient.kt) class into your code and customize it\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your customized client\n\n### Completely custom HTTP client\n\nTo use a completely custom HTTP client:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Write a class that implements the [`HttpClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/http/HttpClient.kt) interface\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your new client class\n\n## Undocumented API functionality\n\nThe SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.\n\n### Parameters\n\nTo set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .putAdditionalHeader("Secret-Header", "42")\n .putAdditionalQueryParam("secret_query_param", "42")\n .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))\n .build();\n```\n\nThese can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.\n\nTo set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\n\nBrandAiQueryParams params = BrandAiQueryParams.builder()\n .specificPages(BrandAiQueryParams.SpecificPages.builder()\n .putAdditionalProperty("secretProperty", JsonValue.from("42"))\n .build())\n .build();\n```\n\nThese properties can be accessed on the nested built object later using the `_additionalProperties()` method.\n\nTo set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) object to its setter:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\n```\n\nThe most straightforward way to create a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) is using its `from(...)` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.List;\nimport java.util.Map;\n\n// Create primitive JSON values\nJsonValue nullValue = JsonValue.from(null);\nJsonValue booleanValue = JsonValue.from(true);\nJsonValue numberValue = JsonValue.from(42);\nJsonValue stringValue = JsonValue.from("Hello World!");\n\n// Create a JSON array value equivalent to `["Hello", "World"]`\nJsonValue arrayValue = JsonValue.from(List.of(\n "Hello", "World"\n));\n\n// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`\nJsonValue objectValue = JsonValue.from(Map.of(\n "a", 1,\n "b", 2\n));\n\n// Create an arbitrarily nested JSON equivalent to:\n// {\n// "a": [1, 2],\n// "b": [3, 4]\n// }\nJsonValue complexValue = JsonValue.from(Map.of(\n "a", List.of(\n 1, 2\n ),\n "b", List.of(\n 3, 4\n )\n));\n```\n\nNormally a `Builder` class\'s `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.\n\nTo forcibly omit a required parameter or property, pass [`JsonMissing`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt):\n\n```java\nimport com.branddev.api.core.JsonMissing;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain(JsonMissing.of())\n .build();\n```\n\n### Response properties\n\nTo access undocumented response properties, call the `_additionalProperties()` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.Map;\n\nMap additionalProperties = client.brand().retrieve(params)._additionalProperties();\nJsonValue secretPropertyValue = additionalProperties.get("secretProperty");\n\nString result = secretPropertyValue.accept(new JsonValue.Visitor<>() {\n @Override\n public String visitNull() {\n return "It\'s null!";\n }\n\n @Override\n public String visitBoolean(boolean value) {\n return "It\'s a boolean!";\n }\n\n @Override\n public String visitNumber(Number value) {\n return "It\'s a number!";\n }\n\n // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`\n // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden\n});\n```\n\nTo access a property\'s raw JSON value, which may be undocumented, call its `_` prefixed method:\n\n```java\nimport com.branddev.api.core.JsonField;\nimport java.util.Optional;\n\nJsonField field = client.brand().retrieve(params)._field();\n\nif (field.isMissing()) {\n // The property is absent from the JSON response\n} else if (field.isNull()) {\n // The property was set to literal null\n} else {\n // Check if value was provided as a string\n // Other methods include `asNumber()`, `asBoolean()`, etc.\n Optional jsonString = field.asString();\n\n // Try to deserialize into a custom type\n MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class);\n}\n```\n\n### Response validation\n\nIn rare cases, the API may return a response that doesn\'t match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.\n\nBy default, the SDK will not throw an exception in this case. It will throw [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt) only if you directly access the property.\n\nIf you would prefer to check that the response is completely well-typed upfront, then either call `validate()`:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(params).validate();\n```\n\nOr configure the method call to validate the response using the `responseValidation` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().responseValidation(true).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .responseValidation(true)\n .build();\n```\n\n## FAQ\n\n### Why don\'t you use plain `enum` classes?\n\nJava `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.\n\n### Why do you represent fields using `JsonField` instead of just plain `T`?\n\nUsing `JsonField` enables a few features:\n\n- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)\n- Lazily [validating the API response against the expected shape](#response-validation)\n- Representing absent vs explicitly null values\n\n### Why don\'t you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?\n\nIt is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don\'t want to introduce a breaking change every time we add a field to a class.\n\n### Why don\'t you use checked exceptions?\n\nChecked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.\n\nChecked exceptions:\n\n- Are verbose to handle\n- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error\n- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)\n- Don\'t play well with lambdas (also due to the function coloring problem)\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-java-sdk/issues) with questions, bugs, or suggestions.\n', + '# Brand Dev Java API Library\n\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.0.1)\n[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1)\n\n\nThe Brand Dev Java SDK provides convenient access to the [Brand Dev REST API](https://docs.context.dev/) from applications written in Java.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1).\n\n\n\n## Installation\n\n\n\n### Gradle\n\n~~~kotlin\nimplementation("com.branddev.api:brand-dev-java:0.0.1")\n~~~\n\n### Maven\n\n~~~xml\n\n com.branddev.api\n brand-dev-java\n 0.0.1\n\n~~~\n\n\n\n## Requirements\n\nThis library requires Java 8 or later.\n\n## Usage\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nBrandRetrieveResponse brand = client.brand().retrieve(params);\n```\n\n## Client configuration\n\nConfigure the client using system properties or environment variables:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n```\n\nOr manually:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .apiKey("My API Key")\n .build();\n```\n\nOr using a combination of the two approaches:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n // Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n // Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\n .fromEnv()\n .apiKey("My API Key")\n .build();\n```\n\nSee this table for the available options:\n\n| Setter | System property | Environment variable | Required | Default value |\n| --------- | ------------------ | -------------------- | -------- | ---------------------------- |\n| `apiKey` | `branddev.apiKey` | `BRAND_DEV_API_KEY` | true | - |\n| `baseUrl` | `branddev.baseUrl` | `BRAND_DEV_BASE_URL` | true | `"https://api.brand.dev/v1"` |\n\nSystem properties take precedence over environment variables.\n\n> [!TIP]\n> Don\'t create more than one client in the same application. Each client has a connection pool and\n> thread pools, which are more efficient to share between requests.\n\n### Modifying configuration\n\nTo temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\n\nBrandDevClient clientWithOptions = client.withOptions(optionsBuilder -> {\n optionsBuilder.baseUrl("https://example.com");\n optionsBuilder.maxRetries(42);\n});\n```\n\nThe `withOptions()` method does not affect the original client or service.\n\n## Requests and responses\n\nTo send a request to the Brand Dev API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.\n\nFor example, `client.brand().retrieve(...)` should be called with an instance of `BrandRetrieveParams`, and it will return an instance of `BrandRetrieveResponse`.\n\n## Immutability\n\nEach class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.\n\nEach class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.\n\nBecause each class is immutable, builder modification will _never_ affect already built class instances.\n\n## Asynchronous execution\n\nThe default client is synchronous. To switch to asynchronous execution, call the `async()` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.async().brand().retrieve(params);\n```\n\nOr create an asynchronous client from the beginning:\n\n```java\nimport com.branddev.api.client.BrandDevClientAsync;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClientAsync;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClientAsync client = BrandDevOkHttpClientAsync.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.brand().retrieve(params);\n```\n\nThe asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.\n\n\n\n\n\n\n\n## Raw responses\n\nThe SDK defines methods that deserialize responses into instances of Java classes. However, these methods don\'t provide access to the response headers, status code, or the raw response body.\n\nTo access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:\n\n```java\nimport com.branddev.api.core.http.Headers;\nimport com.branddev.api.core.http.HttpResponseFor;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nHttpResponseFor brand = client.brand().withRawResponse().retrieve(params);\n\nint statusCode = brand.statusCode();\nHeaders headers = brand.headers();\n```\n\nYou can still deserialize the response into an instance of a Java class if needed:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse parsedBrand = brand.parse();\n```\n\n## Error handling\n\nThe SDK throws custom unchecked exception types:\n\n- [`BrandDevServiceException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:\n\n | Status | Exception |\n | ------ | -------------------------------------------------- |\n | 400 | [`BadRequestException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BadRequestException.kt) |\n | 401 | [`UnauthorizedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnauthorizedException.kt) |\n | 403 | [`PermissionDeniedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/PermissionDeniedException.kt) |\n | 404 | [`NotFoundException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/NotFoundException.kt) |\n | 422 | [`UnprocessableEntityException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnprocessableEntityException.kt) |\n | 429 | [`RateLimitException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/RateLimitException.kt) |\n | 5xx | [`InternalServerException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/InternalServerException.kt) |\n | others | [`UnexpectedStatusCodeException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnexpectedStatusCodeException.kt) |\n\n- [`BrandDevIoException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevIoException.kt): I/O networking errors.\n\n- [`BrandDevRetryableException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevRetryableException.kt): Generic error indicating a failure that could be retried by the client.\n\n- [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that\'s supposed to be required, but the API unexpectedly omitted it from the response.\n\n- [`BrandDevException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.\n\n\n\n## Logging\n\nThe SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).\n\nEnable logging by setting the `BRAND_DEV_LOG` environment variable to `info`:\n\n```sh\nexport BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging:\n\n```sh\nexport BRAND_DEV_LOG=debug\n```\n\n## ProGuard and R8\n\nAlthough the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `brand-dev-java-core` is published with a [configuration file](brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).\n\nProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.\n\n\n\n\n\n## Jackson\n\nThe SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.\n\nThe SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).\n\nIf the SDK threw an exception, but you\'re _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt).\n\n> [!CAUTION]\n> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.\n\nAlso note that there are bugs in older Jackson versions that can affect the SDK. We don\'t work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead.\n\n## Network options\n\n### Retries\n\nThe SDK automatically retries 2 times by default, with a short exponential backoff between requests.\n\nOnly the following error types are retried:\n- Connection errors (for example, due to a network connectivity problem)\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- 5xx Internal\n\nThe API may also explicitly instruct the SDK to retry or not retry a request.\n\nTo set a custom number of retries, configure the client using the `maxRetries` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .maxRetries(4)\n .build();\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default.\n\nTo set a custom timeout, configure the method call using the `timeout` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .timeout(Duration.ofSeconds(30))\n .build();\n```\n\n### Proxies\n\nTo route requests through a proxy, configure the client using the `proxy` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(new Proxy(\n Proxy.Type.HTTP, new InetSocketAddress(\n "https://example.com", 8080\n )\n ))\n .build();\n```\n\n### Connection pooling\n\nTo customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.\n .maxIdleConnections(10)\n .keepAliveDuration(Duration.ofMinutes(2))\n .build();\n```\n\nIf both options are unset, OkHttp\'s default connection pool settings are used.\n\n### HTTPS\n\n> [!NOTE]\n> Most applications should not call these methods, and instead use the system defaults. The defaults include\n> special optimizations that can be lost if the implementations are modified.\n\nTo configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.\n .sslSocketFactory(yourSSLSocketFactory)\n .trustManager(yourTrustManager)\n .hostnameVerifier(yourHostnameVerifier)\n .build();\n```\n\n\n\n### Custom HTTP client\n\nThe SDK consists of three artifacts:\n- `brand-dev-java-core`\n - Contains core SDK logic\n - Does not depend on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClient.kt), [`BrandDevClientAsync`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsync.kt), [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt), and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), all of which can work with any HTTP client\n- `brand-dev-java-client-okhttp`\n - Depends on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) and [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), which provide a way to construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), respectively, using OkHttp\n- `brand-dev-java`\n - Depends on and exposes the APIs of both `brand-dev-java-core` and `brand-dev-java-client-okhttp`\n - Does not have its own logic\n\nThis structure allows replacing the SDK\'s default HTTP client without pulling in unnecessary dependencies.\n\n#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)\n\n> [!TIP]\n> Try the available [network options](#network-options) before replacing the default client.\n\nTo use a customized `OkHttpClient`:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Copy `brand-dev-java-client-okhttp`\'s [`OkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/OkHttpClient.kt) class into your code and customize it\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your customized client\n\n### Completely custom HTTP client\n\nTo use a completely custom HTTP client:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Write a class that implements the [`HttpClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/http/HttpClient.kt) interface\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your new client class\n\n## Undocumented API functionality\n\nThe SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.\n\n### Parameters\n\nTo set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .putAdditionalHeader("Secret-Header", "42")\n .putAdditionalQueryParam("secret_query_param", "42")\n .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))\n .build();\n```\n\nThese can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.\n\nTo set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\n\nBrandAiQueryParams params = BrandAiQueryParams.builder()\n .specificPages(BrandAiQueryParams.SpecificPages.builder()\n .putAdditionalProperty("secretProperty", JsonValue.from("42"))\n .build())\n .build();\n```\n\nThese properties can be accessed on the nested built object later using the `_additionalProperties()` method.\n\nTo set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) object to its setter:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\n```\n\nThe most straightforward way to create a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) is using its `from(...)` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.List;\nimport java.util.Map;\n\n// Create primitive JSON values\nJsonValue nullValue = JsonValue.from(null);\nJsonValue booleanValue = JsonValue.from(true);\nJsonValue numberValue = JsonValue.from(42);\nJsonValue stringValue = JsonValue.from("Hello World!");\n\n// Create a JSON array value equivalent to `["Hello", "World"]`\nJsonValue arrayValue = JsonValue.from(List.of(\n "Hello", "World"\n));\n\n// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`\nJsonValue objectValue = JsonValue.from(Map.of(\n "a", 1,\n "b", 2\n));\n\n// Create an arbitrarily nested JSON equivalent to:\n// {\n// "a": [1, 2],\n// "b": [3, 4]\n// }\nJsonValue complexValue = JsonValue.from(Map.of(\n "a", List.of(\n 1, 2\n ),\n "b", List.of(\n 3, 4\n )\n));\n```\n\nNormally a `Builder` class\'s `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.\n\nTo forcibly omit a required parameter or property, pass [`JsonMissing`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt):\n\n```java\nimport com.branddev.api.core.JsonMissing;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain(JsonMissing.of())\n .build();\n```\n\n### Response properties\n\nTo access undocumented response properties, call the `_additionalProperties()` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.Map;\n\nMap additionalProperties = client.brand().retrieve(params)._additionalProperties();\nJsonValue secretPropertyValue = additionalProperties.get("secretProperty");\n\nString result = secretPropertyValue.accept(new JsonValue.Visitor<>() {\n @Override\n public String visitNull() {\n return "It\'s null!";\n }\n\n @Override\n public String visitBoolean(boolean value) {\n return "It\'s a boolean!";\n }\n\n @Override\n public String visitNumber(Number value) {\n return "It\'s a number!";\n }\n\n // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`\n // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden\n});\n```\n\nTo access a property\'s raw JSON value, which may be undocumented, call its `_` prefixed method:\n\n```java\nimport com.branddev.api.core.JsonField;\nimport java.util.Optional;\n\nJsonField field = client.brand().retrieve(params)._field();\n\nif (field.isMissing()) {\n // The property is absent from the JSON response\n} else if (field.isNull()) {\n // The property was set to literal null\n} else {\n // Check if value was provided as a string\n // Other methods include `asNumber()`, `asBoolean()`, etc.\n Optional jsonString = field.asString();\n\n // Try to deserialize into a custom type\n MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class);\n}\n```\n\n### Response validation\n\nIn rare cases, the API may return a response that doesn\'t match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.\n\nBy default, the SDK will not throw an exception in this case. It will throw [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt) only if you directly access the property.\n\nValidating the response is _not_ forwards compatible with new types from the API for existing fields.\n\nIf you would still prefer to check that the response is completely well-typed upfront, then either call `validate()`:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(params).validate();\n```\n\nOr configure the method call to validate the response using the `responseValidation` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().responseValidation(true).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .responseValidation(true)\n .build();\n```\n\n## FAQ\n\n### Why don\'t you use plain `enum` classes?\n\nJava `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.\n\n### Why do you represent fields using `JsonField` instead of just plain `T`?\n\nUsing `JsonField` enables a few features:\n\n- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)\n- Lazily [validating the API response against the expected shape](#response-validation)\n- Representing absent vs explicitly null values\n\n### Why don\'t you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?\n\nIt is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don\'t want to introduce a breaking change every time we add a field to a class.\n\n### Why don\'t you use checked exceptions?\n\nChecked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.\n\nChecked exceptions:\n\n- Are verbose to handle\n- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error\n- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)\n- Don\'t play well with lambdas (also due to the function coloring problem)\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-java-sdk/issues) with questions, bugs, or suggestions.\n', }, { language: 'python', From c282252b5e88076344bf878241233118211770fa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 05:24:34 +0000 Subject: [PATCH 051/100] docs: update with proxy auth info --- packages/mcp-server/src/local-docs-search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 2819f902..409c82d9 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -737,7 +737,7 @@ const EMBEDDED_READMES: { language: string; content: string }[] = [ { language: 'java', content: - '# Brand Dev Java API Library\n\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.0.1)\n[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1)\n\n\nThe Brand Dev Java SDK provides convenient access to the [Brand Dev REST API](https://docs.context.dev/) from applications written in Java.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1).\n\n\n\n## Installation\n\n\n\n### Gradle\n\n~~~kotlin\nimplementation("com.branddev.api:brand-dev-java:0.0.1")\n~~~\n\n### Maven\n\n~~~xml\n\n com.branddev.api\n brand-dev-java\n 0.0.1\n\n~~~\n\n\n\n## Requirements\n\nThis library requires Java 8 or later.\n\n## Usage\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nBrandRetrieveResponse brand = client.brand().retrieve(params);\n```\n\n## Client configuration\n\nConfigure the client using system properties or environment variables:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n```\n\nOr manually:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .apiKey("My API Key")\n .build();\n```\n\nOr using a combination of the two approaches:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n // Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n // Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\n .fromEnv()\n .apiKey("My API Key")\n .build();\n```\n\nSee this table for the available options:\n\n| Setter | System property | Environment variable | Required | Default value |\n| --------- | ------------------ | -------------------- | -------- | ---------------------------- |\n| `apiKey` | `branddev.apiKey` | `BRAND_DEV_API_KEY` | true | - |\n| `baseUrl` | `branddev.baseUrl` | `BRAND_DEV_BASE_URL` | true | `"https://api.brand.dev/v1"` |\n\nSystem properties take precedence over environment variables.\n\n> [!TIP]\n> Don\'t create more than one client in the same application. Each client has a connection pool and\n> thread pools, which are more efficient to share between requests.\n\n### Modifying configuration\n\nTo temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\n\nBrandDevClient clientWithOptions = client.withOptions(optionsBuilder -> {\n optionsBuilder.baseUrl("https://example.com");\n optionsBuilder.maxRetries(42);\n});\n```\n\nThe `withOptions()` method does not affect the original client or service.\n\n## Requests and responses\n\nTo send a request to the Brand Dev API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.\n\nFor example, `client.brand().retrieve(...)` should be called with an instance of `BrandRetrieveParams`, and it will return an instance of `BrandRetrieveResponse`.\n\n## Immutability\n\nEach class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.\n\nEach class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.\n\nBecause each class is immutable, builder modification will _never_ affect already built class instances.\n\n## Asynchronous execution\n\nThe default client is synchronous. To switch to asynchronous execution, call the `async()` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.async().brand().retrieve(params);\n```\n\nOr create an asynchronous client from the beginning:\n\n```java\nimport com.branddev.api.client.BrandDevClientAsync;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClientAsync;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClientAsync client = BrandDevOkHttpClientAsync.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.brand().retrieve(params);\n```\n\nThe asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.\n\n\n\n\n\n\n\n## Raw responses\n\nThe SDK defines methods that deserialize responses into instances of Java classes. However, these methods don\'t provide access to the response headers, status code, or the raw response body.\n\nTo access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:\n\n```java\nimport com.branddev.api.core.http.Headers;\nimport com.branddev.api.core.http.HttpResponseFor;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nHttpResponseFor brand = client.brand().withRawResponse().retrieve(params);\n\nint statusCode = brand.statusCode();\nHeaders headers = brand.headers();\n```\n\nYou can still deserialize the response into an instance of a Java class if needed:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse parsedBrand = brand.parse();\n```\n\n## Error handling\n\nThe SDK throws custom unchecked exception types:\n\n- [`BrandDevServiceException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:\n\n | Status | Exception |\n | ------ | -------------------------------------------------- |\n | 400 | [`BadRequestException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BadRequestException.kt) |\n | 401 | [`UnauthorizedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnauthorizedException.kt) |\n | 403 | [`PermissionDeniedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/PermissionDeniedException.kt) |\n | 404 | [`NotFoundException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/NotFoundException.kt) |\n | 422 | [`UnprocessableEntityException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnprocessableEntityException.kt) |\n | 429 | [`RateLimitException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/RateLimitException.kt) |\n | 5xx | [`InternalServerException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/InternalServerException.kt) |\n | others | [`UnexpectedStatusCodeException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnexpectedStatusCodeException.kt) |\n\n- [`BrandDevIoException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevIoException.kt): I/O networking errors.\n\n- [`BrandDevRetryableException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevRetryableException.kt): Generic error indicating a failure that could be retried by the client.\n\n- [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that\'s supposed to be required, but the API unexpectedly omitted it from the response.\n\n- [`BrandDevException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.\n\n\n\n## Logging\n\nThe SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).\n\nEnable logging by setting the `BRAND_DEV_LOG` environment variable to `info`:\n\n```sh\nexport BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging:\n\n```sh\nexport BRAND_DEV_LOG=debug\n```\n\n## ProGuard and R8\n\nAlthough the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `brand-dev-java-core` is published with a [configuration file](brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).\n\nProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.\n\n\n\n\n\n## Jackson\n\nThe SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.\n\nThe SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).\n\nIf the SDK threw an exception, but you\'re _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt).\n\n> [!CAUTION]\n> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.\n\nAlso note that there are bugs in older Jackson versions that can affect the SDK. We don\'t work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead.\n\n## Network options\n\n### Retries\n\nThe SDK automatically retries 2 times by default, with a short exponential backoff between requests.\n\nOnly the following error types are retried:\n- Connection errors (for example, due to a network connectivity problem)\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- 5xx Internal\n\nThe API may also explicitly instruct the SDK to retry or not retry a request.\n\nTo set a custom number of retries, configure the client using the `maxRetries` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .maxRetries(4)\n .build();\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default.\n\nTo set a custom timeout, configure the method call using the `timeout` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .timeout(Duration.ofSeconds(30))\n .build();\n```\n\n### Proxies\n\nTo route requests through a proxy, configure the client using the `proxy` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(new Proxy(\n Proxy.Type.HTTP, new InetSocketAddress(\n "https://example.com", 8080\n )\n ))\n .build();\n```\n\n### Connection pooling\n\nTo customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.\n .maxIdleConnections(10)\n .keepAliveDuration(Duration.ofMinutes(2))\n .build();\n```\n\nIf both options are unset, OkHttp\'s default connection pool settings are used.\n\n### HTTPS\n\n> [!NOTE]\n> Most applications should not call these methods, and instead use the system defaults. The defaults include\n> special optimizations that can be lost if the implementations are modified.\n\nTo configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.\n .sslSocketFactory(yourSSLSocketFactory)\n .trustManager(yourTrustManager)\n .hostnameVerifier(yourHostnameVerifier)\n .build();\n```\n\n\n\n### Custom HTTP client\n\nThe SDK consists of three artifacts:\n- `brand-dev-java-core`\n - Contains core SDK logic\n - Does not depend on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClient.kt), [`BrandDevClientAsync`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsync.kt), [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt), and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), all of which can work with any HTTP client\n- `brand-dev-java-client-okhttp`\n - Depends on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) and [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), which provide a way to construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), respectively, using OkHttp\n- `brand-dev-java`\n - Depends on and exposes the APIs of both `brand-dev-java-core` and `brand-dev-java-client-okhttp`\n - Does not have its own logic\n\nThis structure allows replacing the SDK\'s default HTTP client without pulling in unnecessary dependencies.\n\n#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)\n\n> [!TIP]\n> Try the available [network options](#network-options) before replacing the default client.\n\nTo use a customized `OkHttpClient`:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Copy `brand-dev-java-client-okhttp`\'s [`OkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/OkHttpClient.kt) class into your code and customize it\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your customized client\n\n### Completely custom HTTP client\n\nTo use a completely custom HTTP client:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Write a class that implements the [`HttpClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/http/HttpClient.kt) interface\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your new client class\n\n## Undocumented API functionality\n\nThe SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.\n\n### Parameters\n\nTo set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .putAdditionalHeader("Secret-Header", "42")\n .putAdditionalQueryParam("secret_query_param", "42")\n .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))\n .build();\n```\n\nThese can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.\n\nTo set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\n\nBrandAiQueryParams params = BrandAiQueryParams.builder()\n .specificPages(BrandAiQueryParams.SpecificPages.builder()\n .putAdditionalProperty("secretProperty", JsonValue.from("42"))\n .build())\n .build();\n```\n\nThese properties can be accessed on the nested built object later using the `_additionalProperties()` method.\n\nTo set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) object to its setter:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\n```\n\nThe most straightforward way to create a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) is using its `from(...)` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.List;\nimport java.util.Map;\n\n// Create primitive JSON values\nJsonValue nullValue = JsonValue.from(null);\nJsonValue booleanValue = JsonValue.from(true);\nJsonValue numberValue = JsonValue.from(42);\nJsonValue stringValue = JsonValue.from("Hello World!");\n\n// Create a JSON array value equivalent to `["Hello", "World"]`\nJsonValue arrayValue = JsonValue.from(List.of(\n "Hello", "World"\n));\n\n// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`\nJsonValue objectValue = JsonValue.from(Map.of(\n "a", 1,\n "b", 2\n));\n\n// Create an arbitrarily nested JSON equivalent to:\n// {\n// "a": [1, 2],\n// "b": [3, 4]\n// }\nJsonValue complexValue = JsonValue.from(Map.of(\n "a", List.of(\n 1, 2\n ),\n "b", List.of(\n 3, 4\n )\n));\n```\n\nNormally a `Builder` class\'s `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.\n\nTo forcibly omit a required parameter or property, pass [`JsonMissing`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt):\n\n```java\nimport com.branddev.api.core.JsonMissing;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain(JsonMissing.of())\n .build();\n```\n\n### Response properties\n\nTo access undocumented response properties, call the `_additionalProperties()` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.Map;\n\nMap additionalProperties = client.brand().retrieve(params)._additionalProperties();\nJsonValue secretPropertyValue = additionalProperties.get("secretProperty");\n\nString result = secretPropertyValue.accept(new JsonValue.Visitor<>() {\n @Override\n public String visitNull() {\n return "It\'s null!";\n }\n\n @Override\n public String visitBoolean(boolean value) {\n return "It\'s a boolean!";\n }\n\n @Override\n public String visitNumber(Number value) {\n return "It\'s a number!";\n }\n\n // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`\n // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden\n});\n```\n\nTo access a property\'s raw JSON value, which may be undocumented, call its `_` prefixed method:\n\n```java\nimport com.branddev.api.core.JsonField;\nimport java.util.Optional;\n\nJsonField field = client.brand().retrieve(params)._field();\n\nif (field.isMissing()) {\n // The property is absent from the JSON response\n} else if (field.isNull()) {\n // The property was set to literal null\n} else {\n // Check if value was provided as a string\n // Other methods include `asNumber()`, `asBoolean()`, etc.\n Optional jsonString = field.asString();\n\n // Try to deserialize into a custom type\n MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class);\n}\n```\n\n### Response validation\n\nIn rare cases, the API may return a response that doesn\'t match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.\n\nBy default, the SDK will not throw an exception in this case. It will throw [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt) only if you directly access the property.\n\nValidating the response is _not_ forwards compatible with new types from the API for existing fields.\n\nIf you would still prefer to check that the response is completely well-typed upfront, then either call `validate()`:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(params).validate();\n```\n\nOr configure the method call to validate the response using the `responseValidation` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().responseValidation(true).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .responseValidation(true)\n .build();\n```\n\n## FAQ\n\n### Why don\'t you use plain `enum` classes?\n\nJava `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.\n\n### Why do you represent fields using `JsonField` instead of just plain `T`?\n\nUsing `JsonField` enables a few features:\n\n- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)\n- Lazily [validating the API response against the expected shape](#response-validation)\n- Representing absent vs explicitly null values\n\n### Why don\'t you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?\n\nIt is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don\'t want to introduce a breaking change every time we add a field to a class.\n\n### Why don\'t you use checked exceptions?\n\nChecked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.\n\nChecked exceptions:\n\n- Are verbose to handle\n- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error\n- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)\n- Don\'t play well with lambdas (also due to the function coloring problem)\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-java-sdk/issues) with questions, bugs, or suggestions.\n', + '# Brand Dev Java API Library\n\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.0.1)\n[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1)\n\n\nThe Brand Dev Java SDK provides convenient access to the [Brand Dev REST API](https://docs.context.dev/) from applications written in Java.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1).\n\n\n\n## Installation\n\n\n\n### Gradle\n\n~~~kotlin\nimplementation("com.branddev.api:brand-dev-java:0.0.1")\n~~~\n\n### Maven\n\n~~~xml\n\n com.branddev.api\n brand-dev-java\n 0.0.1\n\n~~~\n\n\n\n## Requirements\n\nThis library requires Java 8 or later.\n\n## Usage\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nBrandRetrieveResponse brand = client.brand().retrieve(params);\n```\n\n## Client configuration\n\nConfigure the client using system properties or environment variables:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n```\n\nOr manually:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .apiKey("My API Key")\n .build();\n```\n\nOr using a combination of the two approaches:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n // Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n // Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\n .fromEnv()\n .apiKey("My API Key")\n .build();\n```\n\nSee this table for the available options:\n\n| Setter | System property | Environment variable | Required | Default value |\n| --------- | ------------------ | -------------------- | -------- | ---------------------------- |\n| `apiKey` | `branddev.apiKey` | `BRAND_DEV_API_KEY` | true | - |\n| `baseUrl` | `branddev.baseUrl` | `BRAND_DEV_BASE_URL` | true | `"https://api.brand.dev/v1"` |\n\nSystem properties take precedence over environment variables.\n\n> [!TIP]\n> Don\'t create more than one client in the same application. Each client has a connection pool and\n> thread pools, which are more efficient to share between requests.\n\n### Modifying configuration\n\nTo temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\n\nBrandDevClient clientWithOptions = client.withOptions(optionsBuilder -> {\n optionsBuilder.baseUrl("https://example.com");\n optionsBuilder.maxRetries(42);\n});\n```\n\nThe `withOptions()` method does not affect the original client or service.\n\n## Requests and responses\n\nTo send a request to the Brand Dev API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.\n\nFor example, `client.brand().retrieve(...)` should be called with an instance of `BrandRetrieveParams`, and it will return an instance of `BrandRetrieveResponse`.\n\n## Immutability\n\nEach class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.\n\nEach class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.\n\nBecause each class is immutable, builder modification will _never_ affect already built class instances.\n\n## Asynchronous execution\n\nThe default client is synchronous. To switch to asynchronous execution, call the `async()` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.async().brand().retrieve(params);\n```\n\nOr create an asynchronous client from the beginning:\n\n```java\nimport com.branddev.api.client.BrandDevClientAsync;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClientAsync;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClientAsync client = BrandDevOkHttpClientAsync.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.brand().retrieve(params);\n```\n\nThe asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.\n\n\n\n\n\n\n\n## Raw responses\n\nThe SDK defines methods that deserialize responses into instances of Java classes. However, these methods don\'t provide access to the response headers, status code, or the raw response body.\n\nTo access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:\n\n```java\nimport com.branddev.api.core.http.Headers;\nimport com.branddev.api.core.http.HttpResponseFor;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nHttpResponseFor brand = client.brand().withRawResponse().retrieve(params);\n\nint statusCode = brand.statusCode();\nHeaders headers = brand.headers();\n```\n\nYou can still deserialize the response into an instance of a Java class if needed:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse parsedBrand = brand.parse();\n```\n\n## Error handling\n\nThe SDK throws custom unchecked exception types:\n\n- [`BrandDevServiceException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:\n\n | Status | Exception |\n | ------ | -------------------------------------------------- |\n | 400 | [`BadRequestException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BadRequestException.kt) |\n | 401 | [`UnauthorizedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnauthorizedException.kt) |\n | 403 | [`PermissionDeniedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/PermissionDeniedException.kt) |\n | 404 | [`NotFoundException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/NotFoundException.kt) |\n | 422 | [`UnprocessableEntityException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnprocessableEntityException.kt) |\n | 429 | [`RateLimitException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/RateLimitException.kt) |\n | 5xx | [`InternalServerException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/InternalServerException.kt) |\n | others | [`UnexpectedStatusCodeException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnexpectedStatusCodeException.kt) |\n\n- [`BrandDevIoException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevIoException.kt): I/O networking errors.\n\n- [`BrandDevRetryableException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevRetryableException.kt): Generic error indicating a failure that could be retried by the client.\n\n- [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that\'s supposed to be required, but the API unexpectedly omitted it from the response.\n\n- [`BrandDevException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.\n\n\n\n## Logging\n\nThe SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).\n\nEnable logging by setting the `BRAND_DEV_LOG` environment variable to `info`:\n\n```sh\nexport BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging:\n\n```sh\nexport BRAND_DEV_LOG=debug\n```\n\n## ProGuard and R8\n\nAlthough the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `brand-dev-java-core` is published with a [configuration file](brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).\n\nProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.\n\n\n\n\n\n## Jackson\n\nThe SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.\n\nThe SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).\n\nIf the SDK threw an exception, but you\'re _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt).\n\n> [!CAUTION]\n> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.\n\nAlso note that there are bugs in older Jackson versions that can affect the SDK. We don\'t work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead.\n\n## Network options\n\n### Retries\n\nThe SDK automatically retries 2 times by default, with a short exponential backoff between requests.\n\nOnly the following error types are retried:\n- Connection errors (for example, due to a network connectivity problem)\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- 5xx Internal\n\nThe API may also explicitly instruct the SDK to retry or not retry a request.\n\nTo set a custom number of retries, configure the client using the `maxRetries` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .maxRetries(4)\n .build();\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default.\n\nTo set a custom timeout, configure the method call using the `timeout` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .timeout(Duration.ofSeconds(30))\n .build();\n```\n\n### Proxies\n\nTo route requests through a proxy, configure the client using the `proxy` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(new Proxy(\n Proxy.Type.HTTP, new InetSocketAddress(\n "https://example.com", 8080\n )\n ))\n .build();\n```\n\nIf the proxy responds with `407 Proxy Authentication Required`, supply credentials by also configuring `proxyAuthenticator`:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.core.http.ProxyAuthenticator;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(...)\n // Or a custom implementation of `ProxyAuthenticator`.\n .proxyAuthenticator(ProxyAuthenticator.basic("username", "password"))\n .build();\n```\n\n### Connection pooling\n\nTo customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.\n .maxIdleConnections(10)\n .keepAliveDuration(Duration.ofMinutes(2))\n .build();\n```\n\nIf both options are unset, OkHttp\'s default connection pool settings are used.\n\n### HTTPS\n\n> [!NOTE]\n> Most applications should not call these methods, and instead use the system defaults. The defaults include\n> special optimizations that can be lost if the implementations are modified.\n\nTo configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.\n .sslSocketFactory(yourSSLSocketFactory)\n .trustManager(yourTrustManager)\n .hostnameVerifier(yourHostnameVerifier)\n .build();\n```\n\n\n\n### Custom HTTP client\n\nThe SDK consists of three artifacts:\n- `brand-dev-java-core`\n - Contains core SDK logic\n - Does not depend on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClient.kt), [`BrandDevClientAsync`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsync.kt), [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt), and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), all of which can work with any HTTP client\n- `brand-dev-java-client-okhttp`\n - Depends on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) and [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), which provide a way to construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), respectively, using OkHttp\n- `brand-dev-java`\n - Depends on and exposes the APIs of both `brand-dev-java-core` and `brand-dev-java-client-okhttp`\n - Does not have its own logic\n\nThis structure allows replacing the SDK\'s default HTTP client without pulling in unnecessary dependencies.\n\n#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)\n\n> [!TIP]\n> Try the available [network options](#network-options) before replacing the default client.\n\nTo use a customized `OkHttpClient`:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Copy `brand-dev-java-client-okhttp`\'s [`OkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/OkHttpClient.kt) class into your code and customize it\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your customized client\n\n### Completely custom HTTP client\n\nTo use a completely custom HTTP client:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Write a class that implements the [`HttpClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/http/HttpClient.kt) interface\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your new client class\n\n## Undocumented API functionality\n\nThe SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.\n\n### Parameters\n\nTo set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .putAdditionalHeader("Secret-Header", "42")\n .putAdditionalQueryParam("secret_query_param", "42")\n .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))\n .build();\n```\n\nThese can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.\n\nTo set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\n\nBrandAiQueryParams params = BrandAiQueryParams.builder()\n .specificPages(BrandAiQueryParams.SpecificPages.builder()\n .putAdditionalProperty("secretProperty", JsonValue.from("42"))\n .build())\n .build();\n```\n\nThese properties can be accessed on the nested built object later using the `_additionalProperties()` method.\n\nTo set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) object to its setter:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\n```\n\nThe most straightforward way to create a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) is using its `from(...)` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.List;\nimport java.util.Map;\n\n// Create primitive JSON values\nJsonValue nullValue = JsonValue.from(null);\nJsonValue booleanValue = JsonValue.from(true);\nJsonValue numberValue = JsonValue.from(42);\nJsonValue stringValue = JsonValue.from("Hello World!");\n\n// Create a JSON array value equivalent to `["Hello", "World"]`\nJsonValue arrayValue = JsonValue.from(List.of(\n "Hello", "World"\n));\n\n// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`\nJsonValue objectValue = JsonValue.from(Map.of(\n "a", 1,\n "b", 2\n));\n\n// Create an arbitrarily nested JSON equivalent to:\n// {\n// "a": [1, 2],\n// "b": [3, 4]\n// }\nJsonValue complexValue = JsonValue.from(Map.of(\n "a", List.of(\n 1, 2\n ),\n "b", List.of(\n 3, 4\n )\n));\n```\n\nNormally a `Builder` class\'s `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.\n\nTo forcibly omit a required parameter or property, pass [`JsonMissing`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt):\n\n```java\nimport com.branddev.api.core.JsonMissing;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain(JsonMissing.of())\n .build();\n```\n\n### Response properties\n\nTo access undocumented response properties, call the `_additionalProperties()` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.Map;\n\nMap additionalProperties = client.brand().retrieve(params)._additionalProperties();\nJsonValue secretPropertyValue = additionalProperties.get("secretProperty");\n\nString result = secretPropertyValue.accept(new JsonValue.Visitor<>() {\n @Override\n public String visitNull() {\n return "It\'s null!";\n }\n\n @Override\n public String visitBoolean(boolean value) {\n return "It\'s a boolean!";\n }\n\n @Override\n public String visitNumber(Number value) {\n return "It\'s a number!";\n }\n\n // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`\n // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden\n});\n```\n\nTo access a property\'s raw JSON value, which may be undocumented, call its `_` prefixed method:\n\n```java\nimport com.branddev.api.core.JsonField;\nimport java.util.Optional;\n\nJsonField field = client.brand().retrieve(params)._field();\n\nif (field.isMissing()) {\n // The property is absent from the JSON response\n} else if (field.isNull()) {\n // The property was set to literal null\n} else {\n // Check if value was provided as a string\n // Other methods include `asNumber()`, `asBoolean()`, etc.\n Optional jsonString = field.asString();\n\n // Try to deserialize into a custom type\n MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class);\n}\n```\n\n### Response validation\n\nIn rare cases, the API may return a response that doesn\'t match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.\n\nBy default, the SDK will not throw an exception in this case. It will throw [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt) only if you directly access the property.\n\nValidating the response is _not_ forwards compatible with new types from the API for existing fields.\n\nIf you would still prefer to check that the response is completely well-typed upfront, then either call `validate()`:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(params).validate();\n```\n\nOr configure the method call to validate the response using the `responseValidation` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().responseValidation(true).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .responseValidation(true)\n .build();\n```\n\n## FAQ\n\n### Why don\'t you use plain `enum` classes?\n\nJava `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.\n\n### Why do you represent fields using `JsonField` instead of just plain `T`?\n\nUsing `JsonField` enables a few features:\n\n- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)\n- Lazily [validating the API response against the expected shape](#response-validation)\n- Representing absent vs explicitly null values\n\n### Why don\'t you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?\n\nIt is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don\'t want to introduce a breaking change every time we add a field to a class.\n\n### Why don\'t you use checked exceptions?\n\nChecked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.\n\nChecked exceptions:\n\n- Are verbose to handle\n- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error\n- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)\n- Don\'t play well with lambdas (also due to the function coloring problem)\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-java-sdk/issues) with questions, bugs, or suggestions.\n', }, { language: 'python', From de2b2b76d8d33d290b120327994d047156d77094 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 22:08:28 +0000 Subject: [PATCH 052/100] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 12 +- src/client.ts | 3 - src/internal/qs/LICENSE.md | 13 + src/internal/qs/README.md | 3 + src/internal/qs/formats.ts | 10 + src/internal/qs/index.ts | 13 + src/internal/qs/stringify.ts | 385 +++ src/internal/qs/types.ts | 71 + src/internal/qs/utils.ts | 265 +++ src/internal/utils/query.ts | 20 +- src/resources/brand.ts | 101 +- tests/api-resources/brand.test.ts | 11 +- tests/qs/empty-keys-cases.ts | 271 +++ tests/qs/stringify.test.ts | 2232 ++++++++++++++++++ tests/qs/utils.test.ts | 169 ++ tests/stringifyQuery.test.ts | 6 - 17 files changed, 3544 insertions(+), 45 deletions(-) create mode 100644 src/internal/qs/LICENSE.md create mode 100644 src/internal/qs/README.md create mode 100644 src/internal/qs/formats.ts create mode 100644 src/internal/qs/index.ts create mode 100644 src/internal/qs/stringify.ts create mode 100644 src/internal/qs/types.ts create mode 100644 src/internal/qs/utils.ts create mode 100644 tests/qs/empty-keys-cases.ts create mode 100644 tests/qs/stringify.test.ts create mode 100644 tests/qs/utils.test.ts diff --git a/.stats.yml b/.stats.yml index 6eedefc5..71256d4c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-ca091b4b323baadb654b7292374b8712b6de260f3c1f8f0944caf20795f608ad.yml -openapi_spec_hash: 2bc6f537bfa055541621423722ea85f2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-f4118654961d5928e40ebe0771eb12f9aa1ca68cf9268bf3400eb1ab8b4dae1a.yml +openapi_spec_hash: ff26efd9c23ca8d4ed2c84f1716280c4 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 409c82d9..24d61089 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -656,14 +656,18 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'get', summary: 'Scrape Images', description: - 'Scrapes all images from the given URL. Extracts images from img, svg, picture/source, link, and video elements including inline SVGs, base64 data URIs, and standard URLs.', + 'Extract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.', stainlessPath: '(resource) brand > (method) web_scrape_images', qualified: 'client.brand.webScrapeImages', - params: ['url: string;'], + params: [ + 'url: string;', + 'enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; };', + 'maxAgeMs?: number;', + ], response: - "{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; }[]; success: true; url: string; }", + "{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }", markdown: - "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nScrapes all images from the given URL. Extracts images from img, svg, picture/source, link, and video elements including inline SVGs, base64 data URIs, and standard URLs.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape images from (must include http:// or https:// protocol)\n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 6000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeImages', diff --git a/src/client.ts b/src/client.ts index 82ea7b3d..7f92b6b6 100644 --- a/src/client.ts +++ b/src/client.ts @@ -257,9 +257,6 @@ export class BrandDev { return buildHeaders([{ Authorization: `Bearer ${this.apiKey}` }]); } - /** - * Basic re-implementation of `qs.stringify` for primitive types. - */ protected stringifyQuery(query: object | Record): string { return stringifyQuery(query); } diff --git a/src/internal/qs/LICENSE.md b/src/internal/qs/LICENSE.md new file mode 100644 index 00000000..3fda1573 --- /dev/null +++ b/src/internal/qs/LICENSE.md @@ -0,0 +1,13 @@ +BSD 3-Clause License + +Copyright (c) 2014, Nathan LaFreniere and other [contributors](https://github.com/puruvj/neoqs/graphs/contributors) All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/internal/qs/README.md b/src/internal/qs/README.md new file mode 100644 index 00000000..67ae04ec --- /dev/null +++ b/src/internal/qs/README.md @@ -0,0 +1,3 @@ +# qs + +This is a vendored version of [neoqs](https://github.com/PuruVJ/neoqs) which is a TypeScript rewrite of [qs](https://github.com/ljharb/qs), a query string library. diff --git a/src/internal/qs/formats.ts b/src/internal/qs/formats.ts new file mode 100644 index 00000000..e76a742f --- /dev/null +++ b/src/internal/qs/formats.ts @@ -0,0 +1,10 @@ +import type { Format } from './types'; + +export const default_format: Format = 'RFC3986'; +export const default_formatter = (v: PropertyKey) => String(v); +export const formatters: Record string> = { + RFC1738: (v: PropertyKey) => String(v).replace(/%20/g, '+'), + RFC3986: default_formatter, +}; +export const RFC1738 = 'RFC1738'; +export const RFC3986 = 'RFC3986'; diff --git a/src/internal/qs/index.ts b/src/internal/qs/index.ts new file mode 100644 index 00000000..c3a3620d --- /dev/null +++ b/src/internal/qs/index.ts @@ -0,0 +1,13 @@ +import { default_format, formatters, RFC1738, RFC3986 } from './formats'; + +const formats = { + formatters, + RFC1738, + RFC3986, + default: default_format, +}; + +export { stringify } from './stringify'; +export { formats }; + +export type { DefaultDecoder, DefaultEncoder, Format, ParseOptions, StringifyOptions } from './types'; diff --git a/src/internal/qs/stringify.ts b/src/internal/qs/stringify.ts new file mode 100644 index 00000000..7e71387f --- /dev/null +++ b/src/internal/qs/stringify.ts @@ -0,0 +1,385 @@ +import { encode, is_buffer, maybe_map, has } from './utils'; +import { default_format, default_formatter, formatters } from './formats'; +import type { NonNullableProperties, StringifyOptions } from './types'; +import { isArray } from '../utils/values'; + +const array_prefix_generators = { + brackets(prefix: PropertyKey) { + return String(prefix) + '[]'; + }, + comma: 'comma', + indices(prefix: PropertyKey, key: string) { + return String(prefix) + '[' + key + ']'; + }, + repeat(prefix: PropertyKey) { + return String(prefix); + }, +}; + +const push_to_array = function (arr: any[], value_or_array: any) { + Array.prototype.push.apply(arr, isArray(value_or_array) ? value_or_array : [value_or_array]); +}; + +let toISOString; + +const defaults = { + addQueryPrefix: false, + allowDots: false, + allowEmptyArrays: false, + arrayFormat: 'indices', + charset: 'utf-8', + charsetSentinel: false, + delimiter: '&', + encode: true, + encodeDotInKeys: false, + encoder: encode, + encodeValuesOnly: false, + format: default_format, + formatter: default_formatter, + /** @deprecated */ + indices: false, + serializeDate(date) { + return (toISOString ??= Function.prototype.call.bind(Date.prototype.toISOString))(date); + }, + skipNulls: false, + strictNullHandling: false, +} as NonNullableProperties; + +function is_non_nullish_primitive(v: unknown): v is string | number | boolean | symbol | bigint { + return ( + typeof v === 'string' || + typeof v === 'number' || + typeof v === 'boolean' || + typeof v === 'symbol' || + typeof v === 'bigint' + ); +} + +const sentinel = {}; + +function inner_stringify( + object: any, + prefix: PropertyKey, + generateArrayPrefix: StringifyOptions['arrayFormat'] | ((prefix: string, key: string) => string), + commaRoundTrip: boolean, + allowEmptyArrays: boolean, + strictNullHandling: boolean, + skipNulls: boolean, + encodeDotInKeys: boolean, + encoder: StringifyOptions['encoder'], + filter: StringifyOptions['filter'], + sort: StringifyOptions['sort'], + allowDots: StringifyOptions['allowDots'], + serializeDate: StringifyOptions['serializeDate'], + format: StringifyOptions['format'], + formatter: StringifyOptions['formatter'], + encodeValuesOnly: boolean, + charset: StringifyOptions['charset'], + sideChannel: WeakMap, +) { + let obj = object; + + let tmp_sc = sideChannel; + let step = 0; + let find_flag = false; + while ((tmp_sc = tmp_sc.get(sentinel)) !== void undefined && !find_flag) { + // Where object last appeared in the ref tree + const pos = tmp_sc.get(object); + step += 1; + if (typeof pos !== 'undefined') { + if (pos === step) { + throw new RangeError('Cyclic object value'); + } else { + find_flag = true; // Break while + } + } + if (typeof tmp_sc.get(sentinel) === 'undefined') { + step = 0; + } + } + + if (typeof filter === 'function') { + obj = filter(prefix, obj); + } else if (obj instanceof Date) { + obj = serializeDate?.(obj); + } else if (generateArrayPrefix === 'comma' && isArray(obj)) { + obj = maybe_map(obj, function (value) { + if (value instanceof Date) { + return serializeDate?.(value); + } + return value; + }); + } + + if (obj === null) { + if (strictNullHandling) { + return encoder && !encodeValuesOnly ? + // @ts-expect-error + encoder(prefix, defaults.encoder, charset, 'key', format) + : prefix; + } + + obj = ''; + } + + if (is_non_nullish_primitive(obj) || is_buffer(obj)) { + if (encoder) { + const key_value = + encodeValuesOnly ? prefix + // @ts-expect-error + : encoder(prefix, defaults.encoder, charset, 'key', format); + return [ + formatter?.(key_value) + + '=' + + // @ts-expect-error + formatter?.(encoder(obj, defaults.encoder, charset, 'value', format)), + ]; + } + return [formatter?.(prefix) + '=' + formatter?.(String(obj))]; + } + + const values: string[] = []; + + if (typeof obj === 'undefined') { + return values; + } + + let obj_keys; + if (generateArrayPrefix === 'comma' && isArray(obj)) { + // we need to join elements in + if (encodeValuesOnly && encoder) { + // @ts-expect-error values only + obj = maybe_map(obj, encoder); + } + obj_keys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }]; + } else if (isArray(filter)) { + obj_keys = filter; + } else { + const keys = Object.keys(obj); + obj_keys = sort ? keys.sort(sort) : keys; + } + + const encoded_prefix = encodeDotInKeys ? String(prefix).replace(/\./g, '%2E') : String(prefix); + + const adjusted_prefix = + commaRoundTrip && isArray(obj) && obj.length === 1 ? encoded_prefix + '[]' : encoded_prefix; + + if (allowEmptyArrays && isArray(obj) && obj.length === 0) { + return adjusted_prefix + '[]'; + } + + for (let j = 0; j < obj_keys.length; ++j) { + const key = obj_keys[j]; + const value = + // @ts-ignore + typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key as any]; + + if (skipNulls && value === null) { + continue; + } + + // @ts-ignore + const encoded_key = allowDots && encodeDotInKeys ? (key as any).replace(/\./g, '%2E') : key; + const key_prefix = + isArray(obj) ? + typeof generateArrayPrefix === 'function' ? + generateArrayPrefix(adjusted_prefix, encoded_key) + : adjusted_prefix + : adjusted_prefix + (allowDots ? '.' + encoded_key : '[' + encoded_key + ']'); + + sideChannel.set(object, step); + const valueSideChannel = new WeakMap(); + valueSideChannel.set(sentinel, sideChannel); + push_to_array( + values, + inner_stringify( + value, + key_prefix, + generateArrayPrefix, + commaRoundTrip, + allowEmptyArrays, + strictNullHandling, + skipNulls, + encodeDotInKeys, + // @ts-ignore + generateArrayPrefix === 'comma' && encodeValuesOnly && isArray(obj) ? null : encoder, + filter, + sort, + allowDots, + serializeDate, + format, + formatter, + encodeValuesOnly, + charset, + valueSideChannel, + ), + ); + } + + return values; +} + +function normalize_stringify_options( + opts: StringifyOptions = defaults, +): NonNullableProperties> & { indices?: boolean } { + if (typeof opts.allowEmptyArrays !== 'undefined' && typeof opts.allowEmptyArrays !== 'boolean') { + throw new TypeError('`allowEmptyArrays` option can only be `true` or `false`, when provided'); + } + + if (typeof opts.encodeDotInKeys !== 'undefined' && typeof opts.encodeDotInKeys !== 'boolean') { + throw new TypeError('`encodeDotInKeys` option can only be `true` or `false`, when provided'); + } + + if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') { + throw new TypeError('Encoder has to be a function.'); + } + + const charset = opts.charset || defaults.charset; + if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') { + throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'); + } + + let format = default_format; + if (typeof opts.format !== 'undefined') { + if (!has(formatters, opts.format)) { + throw new TypeError('Unknown format option provided.'); + } + format = opts.format; + } + const formatter = formatters[format]; + + let filter = defaults.filter; + if (typeof opts.filter === 'function' || isArray(opts.filter)) { + filter = opts.filter; + } + + let arrayFormat: StringifyOptions['arrayFormat']; + if (opts.arrayFormat && opts.arrayFormat in array_prefix_generators) { + arrayFormat = opts.arrayFormat; + } else if ('indices' in opts) { + arrayFormat = opts.indices ? 'indices' : 'repeat'; + } else { + arrayFormat = defaults.arrayFormat; + } + + if ('commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') { + throw new TypeError('`commaRoundTrip` must be a boolean, or absent'); + } + + const allowDots = + typeof opts.allowDots === 'undefined' ? + !!opts.encodeDotInKeys === true ? + true + : defaults.allowDots + : !!opts.allowDots; + + return { + addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix, + // @ts-ignore + allowDots: allowDots, + allowEmptyArrays: + typeof opts.allowEmptyArrays === 'boolean' ? !!opts.allowEmptyArrays : defaults.allowEmptyArrays, + arrayFormat: arrayFormat, + charset: charset, + charsetSentinel: + typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel, + commaRoundTrip: !!opts.commaRoundTrip, + delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter, + encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode, + encodeDotInKeys: + typeof opts.encodeDotInKeys === 'boolean' ? opts.encodeDotInKeys : defaults.encodeDotInKeys, + encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder, + encodeValuesOnly: + typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly, + filter: filter, + format: format, + formatter: formatter, + serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults.serializeDate, + skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults.skipNulls, + // @ts-ignore + sort: typeof opts.sort === 'function' ? opts.sort : null, + strictNullHandling: + typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling, + }; +} + +export function stringify(object: any, opts: StringifyOptions = {}) { + let obj = object; + const options = normalize_stringify_options(opts); + + let obj_keys: PropertyKey[] | undefined; + let filter; + + if (typeof options.filter === 'function') { + filter = options.filter; + obj = filter('', obj); + } else if (isArray(options.filter)) { + filter = options.filter; + obj_keys = filter; + } + + const keys: string[] = []; + + if (typeof obj !== 'object' || obj === null) { + return ''; + } + + const generateArrayPrefix = array_prefix_generators[options.arrayFormat]; + const commaRoundTrip = generateArrayPrefix === 'comma' && options.commaRoundTrip; + + if (!obj_keys) { + obj_keys = Object.keys(obj); + } + + if (options.sort) { + obj_keys.sort(options.sort); + } + + const sideChannel = new WeakMap(); + for (let i = 0; i < obj_keys.length; ++i) { + const key = obj_keys[i]!; + + if (options.skipNulls && obj[key] === null) { + continue; + } + push_to_array( + keys, + inner_stringify( + obj[key], + key, + // @ts-expect-error + generateArrayPrefix, + commaRoundTrip, + options.allowEmptyArrays, + options.strictNullHandling, + options.skipNulls, + options.encodeDotInKeys, + options.encode ? options.encoder : null, + options.filter, + options.sort, + options.allowDots, + options.serializeDate, + options.format, + options.formatter, + options.encodeValuesOnly, + options.charset, + sideChannel, + ), + ); + } + + const joined = keys.join(options.delimiter); + let prefix = options.addQueryPrefix === true ? '?' : ''; + + if (options.charsetSentinel) { + if (options.charset === 'iso-8859-1') { + // encodeURIComponent('✓'), the "numeric entity" representation of a checkmark + prefix += 'utf8=%26%2310003%3B&'; + } else { + // encodeURIComponent('✓') + prefix += 'utf8=%E2%9C%93&'; + } + } + + return joined.length > 0 ? prefix + joined : ''; +} diff --git a/src/internal/qs/types.ts b/src/internal/qs/types.ts new file mode 100644 index 00000000..7c28dbb4 --- /dev/null +++ b/src/internal/qs/types.ts @@ -0,0 +1,71 @@ +export type Format = 'RFC1738' | 'RFC3986'; + +export type DefaultEncoder = (str: any, defaultEncoder?: any, charset?: string) => string; +export type DefaultDecoder = (str: string, decoder?: any, charset?: string) => string; + +export type BooleanOptional = boolean | undefined; + +export type StringifyBaseOptions = { + delimiter?: string; + allowDots?: boolean; + encodeDotInKeys?: boolean; + strictNullHandling?: boolean; + skipNulls?: boolean; + encode?: boolean; + encoder?: ( + str: any, + defaultEncoder: DefaultEncoder, + charset: string, + type: 'key' | 'value', + format?: Format, + ) => string; + filter?: Array | ((prefix: PropertyKey, value: any) => any); + arrayFormat?: 'indices' | 'brackets' | 'repeat' | 'comma'; + indices?: boolean; + sort?: ((a: PropertyKey, b: PropertyKey) => number) | null; + serializeDate?: (d: Date) => string; + format?: 'RFC1738' | 'RFC3986'; + formatter?: (str: PropertyKey) => string; + encodeValuesOnly?: boolean; + addQueryPrefix?: boolean; + charset?: 'utf-8' | 'iso-8859-1'; + charsetSentinel?: boolean; + allowEmptyArrays?: boolean; + commaRoundTrip?: boolean; +}; + +export type StringifyOptions = StringifyBaseOptions; + +export type ParseBaseOptions = { + comma?: boolean; + delimiter?: string | RegExp; + depth?: number | false; + decoder?: (str: string, defaultDecoder: DefaultDecoder, charset: string, type: 'key' | 'value') => any; + arrayLimit?: number; + parseArrays?: boolean; + plainObjects?: boolean; + allowPrototypes?: boolean; + allowSparse?: boolean; + parameterLimit?: number; + strictDepth?: boolean; + strictNullHandling?: boolean; + ignoreQueryPrefix?: boolean; + charset?: 'utf-8' | 'iso-8859-1'; + charsetSentinel?: boolean; + interpretNumericEntities?: boolean; + allowEmptyArrays?: boolean; + duplicates?: 'combine' | 'first' | 'last'; + allowDots?: boolean; + decodeDotInKeys?: boolean; +}; + +export type ParseOptions = ParseBaseOptions; + +export type ParsedQs = { + [key: string]: undefined | string | string[] | ParsedQs | ParsedQs[]; +}; + +// Type to remove null or undefined union from each property +export type NonNullableProperties = { + [K in keyof T]-?: Exclude; +}; diff --git a/src/internal/qs/utils.ts b/src/internal/qs/utils.ts new file mode 100644 index 00000000..4cd56579 --- /dev/null +++ b/src/internal/qs/utils.ts @@ -0,0 +1,265 @@ +import { RFC1738 } from './formats'; +import type { DefaultEncoder, Format } from './types'; +import { isArray } from '../utils/values'; + +export let has = (obj: object, key: PropertyKey): boolean => ( + (has = (Object as any).hasOwn ?? Function.prototype.call.bind(Object.prototype.hasOwnProperty)), + has(obj, key) +); + +const hex_table = /* @__PURE__ */ (() => { + const array = []; + for (let i = 0; i < 256; ++i) { + array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase()); + } + + return array; +})(); + +function compact_queue>(queue: Array<{ obj: T; prop: string }>) { + while (queue.length > 1) { + const item = queue.pop(); + if (!item) continue; + + const obj = item.obj[item.prop]; + + if (isArray(obj)) { + const compacted: unknown[] = []; + + for (let j = 0; j < obj.length; ++j) { + if (typeof obj[j] !== 'undefined') { + compacted.push(obj[j]); + } + } + + // @ts-ignore + item.obj[item.prop] = compacted; + } + } +} + +function array_to_object(source: any[], options: { plainObjects: boolean }) { + const obj = options && options.plainObjects ? Object.create(null) : {}; + for (let i = 0; i < source.length; ++i) { + if (typeof source[i] !== 'undefined') { + obj[i] = source[i]; + } + } + + return obj; +} + +export function merge( + target: any, + source: any, + options: { plainObjects?: boolean; allowPrototypes?: boolean } = {}, +) { + if (!source) { + return target; + } + + if (typeof source !== 'object') { + if (isArray(target)) { + target.push(source); + } else if (target && typeof target === 'object') { + if ((options && (options.plainObjects || options.allowPrototypes)) || !has(Object.prototype, source)) { + target[source] = true; + } + } else { + return [target, source]; + } + + return target; + } + + if (!target || typeof target !== 'object') { + return [target].concat(source); + } + + let mergeTarget = target; + if (isArray(target) && !isArray(source)) { + // @ts-ignore + mergeTarget = array_to_object(target, options); + } + + if (isArray(target) && isArray(source)) { + source.forEach(function (item, i) { + if (has(target, i)) { + const targetItem = target[i]; + if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') { + target[i] = merge(targetItem, item, options); + } else { + target.push(item); + } + } else { + target[i] = item; + } + }); + return target; + } + + return Object.keys(source).reduce(function (acc, key) { + const value = source[key]; + + if (has(acc, key)) { + acc[key] = merge(acc[key], value, options); + } else { + acc[key] = value; + } + return acc; + }, mergeTarget); +} + +export function assign_single_source(target: any, source: any) { + return Object.keys(source).reduce(function (acc, key) { + acc[key] = source[key]; + return acc; + }, target); +} + +export function decode(str: string, _: any, charset: string) { + const strWithoutPlus = str.replace(/\+/g, ' '); + if (charset === 'iso-8859-1') { + // unescape never throws, no try...catch needed: + return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape); + } + // utf-8 + try { + return decodeURIComponent(strWithoutPlus); + } catch (e) { + return strWithoutPlus; + } +} + +const limit = 1024; + +export const encode: ( + str: any, + defaultEncoder: DefaultEncoder, + charset: string, + type: 'key' | 'value', + format: Format, +) => string = (str, _defaultEncoder, charset, _kind, format: Format) => { + // This code was originally written by Brian White for the io.js core querystring library. + // It has been adapted here for stricter adherence to RFC 3986 + if (str.length === 0) { + return str; + } + + let string = str; + if (typeof str === 'symbol') { + string = Symbol.prototype.toString.call(str); + } else if (typeof str !== 'string') { + string = String(str); + } + + if (charset === 'iso-8859-1') { + return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) { + return '%26%23' + parseInt($0.slice(2), 16) + '%3B'; + }); + } + + let out = ''; + for (let j = 0; j < string.length; j += limit) { + const segment = string.length >= limit ? string.slice(j, j + limit) : string; + const arr = []; + + for (let i = 0; i < segment.length; ++i) { + let c = segment.charCodeAt(i); + if ( + c === 0x2d || // - + c === 0x2e || // . + c === 0x5f || // _ + c === 0x7e || // ~ + (c >= 0x30 && c <= 0x39) || // 0-9 + (c >= 0x41 && c <= 0x5a) || // a-z + (c >= 0x61 && c <= 0x7a) || // A-Z + (format === RFC1738 && (c === 0x28 || c === 0x29)) // ( ) + ) { + arr[arr.length] = segment.charAt(i); + continue; + } + + if (c < 0x80) { + arr[arr.length] = hex_table[c]; + continue; + } + + if (c < 0x800) { + arr[arr.length] = hex_table[0xc0 | (c >> 6)]! + hex_table[0x80 | (c & 0x3f)]; + continue; + } + + if (c < 0xd800 || c >= 0xe000) { + arr[arr.length] = + hex_table[0xe0 | (c >> 12)]! + hex_table[0x80 | ((c >> 6) & 0x3f)] + hex_table[0x80 | (c & 0x3f)]; + continue; + } + + i += 1; + c = 0x10000 + (((c & 0x3ff) << 10) | (segment.charCodeAt(i) & 0x3ff)); + + arr[arr.length] = + hex_table[0xf0 | (c >> 18)]! + + hex_table[0x80 | ((c >> 12) & 0x3f)] + + hex_table[0x80 | ((c >> 6) & 0x3f)] + + hex_table[0x80 | (c & 0x3f)]; + } + + out += arr.join(''); + } + + return out; +}; + +export function compact(value: any) { + const queue = [{ obj: { o: value }, prop: 'o' }]; + const refs = []; + + for (let i = 0; i < queue.length; ++i) { + const item = queue[i]; + // @ts-ignore + const obj = item.obj[item.prop]; + + const keys = Object.keys(obj); + for (let j = 0; j < keys.length; ++j) { + const key = keys[j]!; + const val = obj[key]; + if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) { + queue.push({ obj: obj, prop: key }); + refs.push(val); + } + } + } + + compact_queue(queue); + + return value; +} + +export function is_regexp(obj: any) { + return Object.prototype.toString.call(obj) === '[object RegExp]'; +} + +export function is_buffer(obj: any) { + if (!obj || typeof obj !== 'object') { + return false; + } + + return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj)); +} + +export function combine(a: any, b: any) { + return [].concat(a, b); +} + +export function maybe_map(val: T[], fn: (v: T) => T) { + if (isArray(val)) { + const mapped = []; + for (let i = 0; i < val.length; i += 1) { + mapped.push(fn(val[i]!)); + } + return mapped; + } + return fn(val); +} diff --git a/src/internal/utils/query.ts b/src/internal/utils/query.ts index 9dc06d9c..0139cacb 100644 --- a/src/internal/utils/query.ts +++ b/src/internal/utils/query.ts @@ -1,23 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { BrandDevError } from '../../core/error'; +import * as qs from '../qs/stringify'; -/** - * Basic re-implementation of `qs.stringify` for primitive types. - */ export function stringifyQuery(query: object | Record) { - return Object.entries(query) - .filter(([_, value]) => typeof value !== 'undefined') - .map(([key, value]) => { - if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { - return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; - } - if (value === null) { - return `${encodeURIComponent(key)}=`; - } - throw new BrandDevError( - `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`, - ); - }) - .join('&'); + return qs.stringify(query, { arrayFormat: 'comma' }); } diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 2a1a132c..77672793 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -137,9 +137,10 @@ export class Brand extends APIResource { } /** - * Scrapes all images from the given URL. Extracts images from img, svg, - * picture/source, link, and video elements including inline SVGs, base64 data - * URIs, and standard URLs. + * Extract image assets from a web page, including standard URLs, inline SVGs, data + * URIs, responsive image sources, metadata, CSS backgrounds, video posters, and + * embeds. The base request costs 1 credit; enrichment costs 1 credit per returned + * image. */ webScrapeImages( query: BrandWebScrapeImagesParams, @@ -5150,17 +5151,17 @@ export interface BrandWebScrapeHTMLResponse { export interface BrandWebScrapeImagesResponse { /** - * Array of scraped images + * Images found on the page. */ images: Array; /** - * Indicates success + * Always true on success. */ success: true; /** - * The URL that was scraped + * Page URL that was scraped. */ url: string; } @@ -5168,24 +5169,61 @@ export interface BrandWebScrapeImagesResponse { export namespace BrandWebScrapeImagesResponse { export interface Image { /** - * Alt text of the image, or null if not present + * Image alt text, or null when unavailable. */ alt: string | null; /** - * The HTML element the image was found in + * Where the image was found. */ element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; /** - * The image source - can be a URL, inline HTML (for SVGs), or a base64 data URI + * Original image value: URL, inline SVG or HTML, or base64 data URI. */ src: string; /** - * The type/format of the src value + * Format of src. */ type: 'url' | 'html' | 'base64'; + + /** + * Requested metadata for images that could be processed. + */ + enrichment?: Image.Enrichment; + } + + export namespace Image { + /** + * Requested metadata for images that could be processed. + */ + export interface Enrichment { + /** + * Image height in pixels, when measured. + */ + height?: number; + + /** + * Detected MIME type, when hosted. + */ + mimetype?: string; + + /** + * Visual asset category, when classified. + */ + type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; + + /** + * Brand.dev CDN URL, when hosted. + */ + url?: string; + + /** + * Image width in pixels, when measured. + */ + width?: number; + } } } @@ -6984,9 +7022,50 @@ export interface BrandWebScrapeHTMLParams { export interface BrandWebScrapeImagesParams { /** - * Full URL to scrape images from (must include http:// or https:// protocol) + * Page URL to inspect. Must include http:// or https://. */ url: string; + + /** + * Optional per-image processing, sent as deep-object query params such as + * enrichment[resolution]=true. + */ + enrichment?: BrandWebScrapeImagesParams.Enrichment; + + /** + * Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 + * day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days). + */ + maxAgeMs?: number; +} + +export namespace BrandWebScrapeImagesParams { + /** + * Optional per-image processing, sent as deep-object query params such as + * enrichment[resolution]=true. + */ + export interface Enrichment { + /** + * Classify each image by visual asset type. + */ + classification?: boolean; + + /** + * Host materializable images on the Brand.dev CDN and return their URL and MIME + * type. + */ + hostedUrl?: boolean; + + /** + * Per-image enrichment timeout in milliseconds. Default: 6000. Maximum: 60000. + */ + maxTimePerMs?: number; + + /** + * Measure image width and height when possible. + */ + resolution?: boolean; + } } export interface BrandWebScrapeMdParams { diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index c76b098c..0cb92a68 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -328,7 +328,16 @@ describe('resource brand', () => { // Mock server tests are disabled test.skip('webScrapeImages: required and optional params', async () => { - const response = await client.brand.webScrapeImages({ url: 'https://example.com' }); + const response = await client.brand.webScrapeImages({ + url: 'https://example.com', + enrichment: { + classification: true, + hostedUrl: true, + maxTimePerMs: 1, + resolution: true, + }, + maxAgeMs: 0, + }); }); // Mock server tests are disabled diff --git a/tests/qs/empty-keys-cases.ts b/tests/qs/empty-keys-cases.ts new file mode 100644 index 00000000..ea2c1b0a --- /dev/null +++ b/tests/qs/empty-keys-cases.ts @@ -0,0 +1,271 @@ +export const empty_test_cases = [ + { + input: '&', + with_empty_keys: {}, + stringify_output: { + brackets: '', + indices: '', + repeat: '', + }, + no_empty_keys: {}, + }, + { + input: '&&', + with_empty_keys: {}, + stringify_output: { + brackets: '', + indices: '', + repeat: '', + }, + no_empty_keys: {}, + }, + { + input: '&=', + with_empty_keys: { '': '' }, + stringify_output: { + brackets: '=', + indices: '=', + repeat: '=', + }, + no_empty_keys: {}, + }, + { + input: '&=&', + with_empty_keys: { '': '' }, + stringify_output: { + brackets: '=', + indices: '=', + repeat: '=', + }, + no_empty_keys: {}, + }, + { + input: '&=&=', + with_empty_keys: { '': ['', ''] }, + stringify_output: { + brackets: '[]=&[]=', + indices: '[0]=&[1]=', + repeat: '=&=', + }, + no_empty_keys: {}, + }, + { + input: '&=&=&', + with_empty_keys: { '': ['', ''] }, + stringify_output: { + brackets: '[]=&[]=', + indices: '[0]=&[1]=', + repeat: '=&=', + }, + no_empty_keys: {}, + }, + { + input: '=', + with_empty_keys: { '': '' }, + no_empty_keys: {}, + stringify_output: { + brackets: '=', + indices: '=', + repeat: '=', + }, + }, + { + input: '=&', + with_empty_keys: { '': '' }, + stringify_output: { + brackets: '=', + indices: '=', + repeat: '=', + }, + no_empty_keys: {}, + }, + { + input: '=&&&', + with_empty_keys: { '': '' }, + stringify_output: { + brackets: '=', + indices: '=', + repeat: '=', + }, + no_empty_keys: {}, + }, + { + input: '=&=&=&', + with_empty_keys: { '': ['', '', ''] }, + stringify_output: { + brackets: '[]=&[]=&[]=', + indices: '[0]=&[1]=&[2]=', + repeat: '=&=&=', + }, + no_empty_keys: {}, + }, + { + input: '=&a[]=b&a[1]=c', + with_empty_keys: { '': '', a: ['b', 'c'] }, + stringify_output: { + brackets: '=&a[]=b&a[]=c', + indices: '=&a[0]=b&a[1]=c', + repeat: '=&a=b&a=c', + }, + no_empty_keys: { a: ['b', 'c'] }, + }, + { + input: '=a', + with_empty_keys: { '': 'a' }, + no_empty_keys: {}, + stringify_output: { + brackets: '=a', + indices: '=a', + repeat: '=a', + }, + }, + { + input: 'a==a', + with_empty_keys: { a: '=a' }, + no_empty_keys: { a: '=a' }, + stringify_output: { + brackets: 'a==a', + indices: 'a==a', + repeat: 'a==a', + }, + }, + { + input: '=&a[]=b', + with_empty_keys: { '': '', a: ['b'] }, + stringify_output: { + brackets: '=&a[]=b', + indices: '=&a[0]=b', + repeat: '=&a=b', + }, + no_empty_keys: { a: ['b'] }, + }, + { + input: '=&a[]=b&a[]=c&a[2]=d', + with_empty_keys: { '': '', a: ['b', 'c', 'd'] }, + stringify_output: { + brackets: '=&a[]=b&a[]=c&a[]=d', + indices: '=&a[0]=b&a[1]=c&a[2]=d', + repeat: '=&a=b&a=c&a=d', + }, + no_empty_keys: { a: ['b', 'c', 'd'] }, + }, + { + input: '=a&=b', + with_empty_keys: { '': ['a', 'b'] }, + stringify_output: { + brackets: '[]=a&[]=b', + indices: '[0]=a&[1]=b', + repeat: '=a&=b', + }, + no_empty_keys: {}, + }, + { + input: '=a&foo=b', + with_empty_keys: { '': 'a', foo: 'b' }, + no_empty_keys: { foo: 'b' }, + stringify_output: { + brackets: '=a&foo=b', + indices: '=a&foo=b', + repeat: '=a&foo=b', + }, + }, + { + input: 'a[]=b&a=c&=', + with_empty_keys: { '': '', a: ['b', 'c'] }, + stringify_output: { + brackets: '=&a[]=b&a[]=c', + indices: '=&a[0]=b&a[1]=c', + repeat: '=&a=b&a=c', + }, + no_empty_keys: { a: ['b', 'c'] }, + }, + { + input: 'a[]=b&a=c&=', + with_empty_keys: { '': '', a: ['b', 'c'] }, + stringify_output: { + brackets: '=&a[]=b&a[]=c', + indices: '=&a[0]=b&a[1]=c', + repeat: '=&a=b&a=c', + }, + no_empty_keys: { a: ['b', 'c'] }, + }, + { + input: 'a[0]=b&a=c&=', + with_empty_keys: { '': '', a: ['b', 'c'] }, + stringify_output: { + brackets: '=&a[]=b&a[]=c', + indices: '=&a[0]=b&a[1]=c', + repeat: '=&a=b&a=c', + }, + no_empty_keys: { a: ['b', 'c'] }, + }, + { + input: 'a=b&a[]=c&=', + with_empty_keys: { '': '', a: ['b', 'c'] }, + stringify_output: { + brackets: '=&a[]=b&a[]=c', + indices: '=&a[0]=b&a[1]=c', + repeat: '=&a=b&a=c', + }, + no_empty_keys: { a: ['b', 'c'] }, + }, + { + input: 'a=b&a[0]=c&=', + with_empty_keys: { '': '', a: ['b', 'c'] }, + stringify_output: { + brackets: '=&a[]=b&a[]=c', + indices: '=&a[0]=b&a[1]=c', + repeat: '=&a=b&a=c', + }, + no_empty_keys: { a: ['b', 'c'] }, + }, + { + input: '[]=a&[]=b& []=1', + with_empty_keys: { '': ['a', 'b'], ' ': ['1'] }, + stringify_output: { + brackets: '[]=a&[]=b& []=1', + indices: '[0]=a&[1]=b& [0]=1', + repeat: '=a&=b& =1', + }, + no_empty_keys: { 0: 'a', 1: 'b', ' ': ['1'] }, + }, + { + input: '[0]=a&[1]=b&a[0]=1&a[1]=2', + with_empty_keys: { '': ['a', 'b'], a: ['1', '2'] }, + no_empty_keys: { 0: 'a', 1: 'b', a: ['1', '2'] }, + stringify_output: { + brackets: '[]=a&[]=b&a[]=1&a[]=2', + indices: '[0]=a&[1]=b&a[0]=1&a[1]=2', + repeat: '=a&=b&a=1&a=2', + }, + }, + { + input: '[deep]=a&[deep]=2', + with_empty_keys: { '': { deep: ['a', '2'] } }, + stringify_output: { + brackets: '[deep][]=a&[deep][]=2', + indices: '[deep][0]=a&[deep][1]=2', + repeat: '[deep]=a&[deep]=2', + }, + no_empty_keys: { deep: ['a', '2'] }, + }, + { + input: '%5B0%5D=a&%5B1%5D=b', + with_empty_keys: { '': ['a', 'b'] }, + stringify_output: { + brackets: '[]=a&[]=b', + indices: '[0]=a&[1]=b', + repeat: '=a&=b', + }, + no_empty_keys: { 0: 'a', 1: 'b' }, + }, +] satisfies { + input: string; + with_empty_keys: Record; + stringify_output: { + brackets: string; + indices: string; + repeat: string; + }; + no_empty_keys: Record; +}[]; diff --git a/tests/qs/stringify.test.ts b/tests/qs/stringify.test.ts new file mode 100644 index 00000000..74e4af88 --- /dev/null +++ b/tests/qs/stringify.test.ts @@ -0,0 +1,2232 @@ +import iconv from 'iconv-lite'; +import { stringify } from 'brand.dev/internal/qs'; +import { encode } from 'brand.dev/internal/qs/utils'; +import { StringifyOptions } from 'brand.dev/internal/qs/types'; +import { empty_test_cases } from './empty-keys-cases'; +import assert from 'assert'; + +describe('stringify()', function () { + test('stringifies a querystring object', function () { + expect(stringify({ a: 'b' })).toBe('a=b'); + expect(stringify({ a: 1 })).toBe('a=1'); + expect(stringify({ a: 1, b: 2 })).toBe('a=1&b=2'); + expect(stringify({ a: 'A_Z' })).toBe('a=A_Z'); + expect(stringify({ a: '€' })).toBe('a=%E2%82%AC'); + expect(stringify({ a: '' })).toBe('a=%EE%80%80'); + expect(stringify({ a: 'א' })).toBe('a=%D7%90'); + expect(stringify({ a: '𐐷' })).toBe('a=%F0%90%90%B7'); + }); + + test('stringifies falsy values', function () { + expect(stringify(undefined)).toBe(''); + expect(stringify(null)).toBe(''); + expect(stringify(null, { strictNullHandling: true })).toBe(''); + expect(stringify(false)).toBe(''); + expect(stringify(0)).toBe(''); + }); + + test('stringifies symbols', function () { + expect(stringify(Symbol.iterator)).toBe(''); + expect(stringify([Symbol.iterator])).toBe('0=Symbol%28Symbol.iterator%29'); + expect(stringify({ a: Symbol.iterator })).toBe('a=Symbol%28Symbol.iterator%29'); + expect(stringify({ a: [Symbol.iterator] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe( + 'a[]=Symbol%28Symbol.iterator%29', + ); + }); + + test('stringifies bigints', function () { + var three = BigInt(3); + // @ts-expect-error + var encodeWithN = function (value, defaultEncoder, charset) { + var result = defaultEncoder(value, defaultEncoder, charset); + return typeof value === 'bigint' ? result + 'n' : result; + }; + + expect(stringify(three)).toBe(''); + expect(stringify([three])).toBe('0=3'); + expect(stringify([three], { encoder: encodeWithN })).toBe('0=3n'); + expect(stringify({ a: three })).toBe('a=3'); + expect(stringify({ a: three }, { encoder: encodeWithN })).toBe('a=3n'); + expect(stringify({ a: [three] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe('a[]=3'); + expect( + stringify({ a: [three] }, { encodeValuesOnly: true, encoder: encodeWithN, arrayFormat: 'brackets' }), + ).toBe('a[]=3n'); + }); + + test('encodes dot in key of object when encodeDotInKeys and allowDots is provided', function () { + expect( + stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: false, encodeDotInKeys: false }), + ).toBe('name.obj%5Bfirst%5D=John&name.obj%5Blast%5D=Doe'); + expect( + stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: true, encodeDotInKeys: false }), + ).toBe('name.obj.first=John&name.obj.last=Doe'); + expect( + stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: false, encodeDotInKeys: true }), + ).toBe('name%252Eobj%5Bfirst%5D=John&name%252Eobj%5Blast%5D=Doe'); + expect( + stringify({ 'name.obj': { first: 'John', last: 'Doe' } }, { allowDots: true, encodeDotInKeys: true }), + ).toBe('name%252Eobj.first=John&name%252Eobj.last=Doe'); + + // st.equal( + // stringify( + // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + // { allowDots: false, encodeDotInKeys: false }, + // ), + // 'name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe', + // 'with allowDots false and encodeDotInKeys false', + // ); + // st.equal( + // stringify( + // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + // { allowDots: true, encodeDotInKeys: false }, + // ), + // 'name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe', + // 'with allowDots false and encodeDotInKeys false', + // ); + // st.equal( + // stringify( + // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + // { allowDots: false, encodeDotInKeys: true }, + // ), + // 'name%252Eobj%252Esubobject%5Bfirst.godly.name%5D=John&name%252Eobj%252Esubobject%5Blast%5D=Doe', + // 'with allowDots false and encodeDotInKeys true', + // ); + // st.equal( + // stringify( + // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + // { allowDots: true, encodeDotInKeys: true }, + // ), + // 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe', + // 'with allowDots true and encodeDotInKeys true', + // ); + expect( + stringify( + { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + { allowDots: false, encodeDotInKeys: false }, + ), + ).toBe('name.obj.subobject%5Bfirst.godly.name%5D=John&name.obj.subobject%5Blast%5D=Doe'); + expect( + stringify( + { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + { allowDots: true, encodeDotInKeys: false }, + ), + ).toBe('name.obj.subobject.first.godly.name=John&name.obj.subobject.last=Doe'); + expect( + stringify( + { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + { allowDots: false, encodeDotInKeys: true }, + ), + ).toBe('name%252Eobj%252Esubobject%5Bfirst.godly.name%5D=John&name%252Eobj%252Esubobject%5Blast%5D=Doe'); + expect( + stringify( + { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + { allowDots: true, encodeDotInKeys: true }, + ), + ).toBe('name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe'); + }); + + test('should encode dot in key of object, and automatically set allowDots to `true` when encodeDotInKeys is true and allowDots in undefined', function () { + // st.equal( + // stringify( + // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + // { encodeDotInKeys: true }, + // ), + // 'name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe', + // 'with allowDots undefined and encodeDotInKeys true', + // ); + expect( + stringify( + { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + { encodeDotInKeys: true }, + ), + ).toBe('name%252Eobj%252Esubobject.first%252Egodly%252Ename=John&name%252Eobj%252Esubobject.last=Doe'); + }); + + test('should encode dot in key of object when encodeDotInKeys and allowDots is provided, and nothing else when encodeValuesOnly is provided', function () { + // st.equal( + // stringify( + // { 'name.obj': { first: 'John', last: 'Doe' } }, + // { + // encodeDotInKeys: true, + // allowDots: true, + // encodeValuesOnly: true, + // }, + // ), + // 'name%2Eobj.first=John&name%2Eobj.last=Doe', + // ); + expect( + stringify( + { 'name.obj': { first: 'John', last: 'Doe' } }, + { + encodeDotInKeys: true, + allowDots: true, + encodeValuesOnly: true, + }, + ), + ).toBe('name%2Eobj.first=John&name%2Eobj.last=Doe'); + + // st.equal( + // stringify( + // { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + // { allowDots: true, encodeDotInKeys: true, encodeValuesOnly: true }, + // ), + // 'name%2Eobj%2Esubobject.first%2Egodly%2Ename=John&name%2Eobj%2Esubobject.last=Doe', + // ); + expect( + stringify( + { 'name.obj.subobject': { 'first.godly.name': 'John', last: 'Doe' } }, + { allowDots: true, encodeDotInKeys: true, encodeValuesOnly: true }, + ), + ).toBe('name%2Eobj%2Esubobject.first%2Egodly%2Ename=John&name%2Eobj%2Esubobject.last=Doe'); + }); + + test('throws when `commaRoundTrip` is not a boolean', function () { + // st['throws']( + // function () { + // stringify({}, { commaRoundTrip: 'not a boolean' }); + // }, + // TypeError, + // 'throws when `commaRoundTrip` is not a boolean', + // ); + expect(() => { + // @ts-expect-error + stringify({}, { commaRoundTrip: 'not a boolean' }); + }).toThrow(TypeError); + }); + + test('throws when `encodeDotInKeys` is not a boolean', function () { + // st['throws'](function () { + // stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 'foobar' }); + // }, TypeError); + expect(() => { + // @ts-expect-error + stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 'foobar' }); + }).toThrow(TypeError); + + // st['throws'](function () { + // stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 0 }); + // }, TypeError); + expect(() => { + // @ts-expect-error + stringify({ a: [], b: 'zz' }, { encodeDotInKeys: 0 }); + }).toThrow(TypeError); + + // st['throws'](function () { + // stringify({ a: [], b: 'zz' }, { encodeDotInKeys: NaN }); + // }, TypeError); + expect(() => { + // @ts-expect-error + stringify({ a: [], b: 'zz' }, { encodeDotInKeys: NaN }); + }).toThrow(TypeError); + + // st['throws'](function () { + // stringify({ a: [], b: 'zz' }, { encodeDotInKeys: null }); + // }, TypeError); + expect(() => { + // @ts-expect-error + stringify({ a: [], b: 'zz' }, { encodeDotInKeys: null }); + }).toThrow(TypeError); + }); + + test('adds query prefix', function () { + // st.equal(stringify({ a: 'b' }, { addQueryPrefix: true }), '?a=b'); + expect(stringify({ a: 'b' }, { addQueryPrefix: true })).toBe('?a=b'); + }); + + test('with query prefix, outputs blank string given an empty object', function () { + // st.equal(stringify({}, { addQueryPrefix: true }), ''); + expect(stringify({}, { addQueryPrefix: true })).toBe(''); + }); + + test('stringifies nested falsy values', function () { + // st.equal(stringify({ a: { b: { c: null } } }), 'a%5Bb%5D%5Bc%5D='); + // st.equal( + // stringify({ a: { b: { c: null } } }, { strictNullHandling: true }), + // 'a%5Bb%5D%5Bc%5D', + // ); + // st.equal(stringify({ a: { b: { c: false } } }), 'a%5Bb%5D%5Bc%5D=false'); + expect(stringify({ a: { b: { c: null } } })).toBe('a%5Bb%5D%5Bc%5D='); + expect(stringify({ a: { b: { c: null } } }, { strictNullHandling: true })).toBe('a%5Bb%5D%5Bc%5D'); + expect(stringify({ a: { b: { c: false } } })).toBe('a%5Bb%5D%5Bc%5D=false'); + }); + + test('stringifies a nested object', function () { + // st.equal(stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c'); + // st.equal(stringify({ a: { b: { c: { d: 'e' } } } }), 'a%5Bb%5D%5Bc%5D%5Bd%5D=e'); + expect(stringify({ a: { b: 'c' } })).toBe('a%5Bb%5D=c'); + expect(stringify({ a: { b: { c: { d: 'e' } } } })).toBe('a%5Bb%5D%5Bc%5D%5Bd%5D=e'); + }); + + test('`allowDots` option: stringifies a nested object with dots notation', function () { + // st.equal(stringify({ a: { b: 'c' } }, { allowDots: true }), 'a.b=c'); + // st.equal(stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true }), 'a.b.c.d=e'); + expect(stringify({ a: { b: 'c' } }, { allowDots: true })).toBe('a.b=c'); + expect(stringify({ a: { b: { c: { d: 'e' } } } }, { allowDots: true })).toBe('a.b.c.d=e'); + }); + + test('stringifies an array value', function () { + // st.equal( + // stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'indices' }), + // 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d', + // 'indices => indices', + // ); + // st.equal( + // stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'brackets' }), + // 'a%5B%5D=b&a%5B%5D=c&a%5B%5D=d', + // 'brackets => brackets', + // ); + // st.equal( + // stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma' }), + // 'a=b%2Cc%2Cd', + // 'comma => comma', + // ); + // st.equal( + // stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma', commaRoundTrip: true }), + // 'a=b%2Cc%2Cd', + // 'comma round trip => comma', + // ); + // st.equal( + // stringify({ a: ['b', 'c', 'd'] }), + // 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d', + // 'default => indices', + // ); + expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'indices' })).toBe( + 'a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d', + ); + expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'brackets' })).toBe( + 'a%5B%5D=b&a%5B%5D=c&a%5B%5D=d', + ); + expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma' })).toBe('a=b%2Cc%2Cd'); + expect(stringify({ a: ['b', 'c', 'd'] }, { arrayFormat: 'comma', commaRoundTrip: true })).toBe( + 'a=b%2Cc%2Cd', + ); + expect(stringify({ a: ['b', 'c', 'd'] })).toBe('a%5B0%5D=b&a%5B1%5D=c&a%5B2%5D=d'); + }); + + test('`skipNulls` option', function () { + // st.equal( + // stringify({ a: 'b', c: null }, { skipNulls: true }), + // 'a=b', + // 'omits nulls when asked', + // ); + expect(stringify({ a: 'b', c: null }, { skipNulls: true })).toBe('a=b'); + + // st.equal( + // stringify({ a: { b: 'c', d: null } }, { skipNulls: true }), + // 'a%5Bb%5D=c', + // 'omits nested nulls when asked', + // ); + expect(stringify({ a: { b: 'c', d: null } }, { skipNulls: true })).toBe('a%5Bb%5D=c'); + }); + + test('omits array indices when asked', function () { + // st.equal(stringify({ a: ['b', 'c', 'd'] }, { indices: false }), 'a=b&a=c&a=d'); + expect(stringify({ a: ['b', 'c', 'd'] }, { indices: false })).toBe('a=b&a=c&a=d'); + }); + + test('omits object key/value pair when value is empty array', function () { + // st.equal(stringify({ a: [], b: 'zz' }), 'b=zz'); + expect(stringify({ a: [], b: 'zz' })).toBe('b=zz'); + }); + + test('should not omit object key/value pair when value is empty array and when asked', function () { + // st.equal(stringify({ a: [], b: 'zz' }), 'b=zz'); + // st.equal(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: false }), 'b=zz'); + // st.equal(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: true }), 'a[]&b=zz'); + expect(stringify({ a: [], b: 'zz' })).toBe('b=zz'); + expect(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: false })).toBe('b=zz'); + expect(stringify({ a: [], b: 'zz' }, { allowEmptyArrays: true })).toBe('a[]&b=zz'); + }); + + test('should throw when allowEmptyArrays is not of type boolean', function () { + // st['throws'](function () { + // stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 'foobar' }); + // }, TypeError); + expect(() => { + // @ts-expect-error + stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 'foobar' }); + }).toThrow(TypeError); + + // st['throws'](function () { + // stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 0 }); + // }, TypeError); + expect(() => { + // @ts-expect-error + stringify({ a: [], b: 'zz' }, { allowEmptyArrays: 0 }); + }).toThrow(TypeError); + + // st['throws'](function () { + // stringify({ a: [], b: 'zz' }, { allowEmptyArrays: NaN }); + // }, TypeError); + expect(() => { + // @ts-expect-error + stringify({ a: [], b: 'zz' }, { allowEmptyArrays: NaN }); + }).toThrow(TypeError); + + // st['throws'](function () { + // stringify({ a: [], b: 'zz' }, { allowEmptyArrays: null }); + // }, TypeError); + expect(() => { + // @ts-expect-error + stringify({ a: [], b: 'zz' }, { allowEmptyArrays: null }); + }).toThrow(TypeError); + }); + + test('allowEmptyArrays + strictNullHandling', function () { + // st.equal( + // stringify({ testEmptyArray: [] }, { strictNullHandling: true, allowEmptyArrays: true }), + // 'testEmptyArray[]', + // ); + expect(stringify({ testEmptyArray: [] }, { strictNullHandling: true, allowEmptyArrays: true })).toBe( + 'testEmptyArray[]', + ); + }); + + describe('stringifies an array value with one item vs multiple items', function () { + test('non-array item', function () { + // s2t.equal( + // stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'indices' }), + // 'a=c', + // ); + // s2t.equal( + // stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + // 'a=c', + // ); + // s2t.equal(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'comma' }), 'a=c'); + // s2t.equal(stringify({ a: 'c' }, { encodeValuesOnly: true }), 'a=c'); + expect(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe('a=c'); + expect(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe('a=c'); + expect(stringify({ a: 'c' }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe('a=c'); + expect(stringify({ a: 'c' }, { encodeValuesOnly: true })).toBe('a=c'); + }); + + test('array with a single item', function () { + // s2t.equal( + // stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), + // 'a[0]=c', + // ); + // s2t.equal( + // stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + // 'a[]=c', + // ); + // s2t.equal( + // stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), + // 'a=c', + // ); + // s2t.equal( + // stringify( + // { a: ['c'] }, + // { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }, + // ), + // 'a[]=c', + // ); // so it parses back as an array + // s2t.equal(stringify({ a: ['c'] }, { encodeValuesOnly: true }), 'a[0]=c'); + expect(stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe('a[0]=c'); + expect(stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe('a[]=c'); + expect(stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe('a=c'); + expect( + stringify({ a: ['c'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), + ).toBe('a[]=c'); + expect(stringify({ a: ['c'] }, { encodeValuesOnly: true })).toBe('a[0]=c'); + }); + + test('array with multiple items', function () { + // s2t.equal( + // stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), + // 'a[0]=c&a[1]=d', + // ); + // s2t.equal( + // stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + // 'a[]=c&a[]=d', + // ); + // s2t.equal( + // stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), + // 'a=c,d', + // ); + // s2t.equal( + // stringify( + // { a: ['c', 'd'] }, + // { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }, + // ), + // 'a=c,d', + // ); + // s2t.equal(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true }), 'a[0]=c&a[1]=d'); + expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe( + 'a[0]=c&a[1]=d', + ); + expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe( + 'a[]=c&a[]=d', + ); + expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe('a=c,d'); + expect( + stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }), + ).toBe('a=c,d'); + expect(stringify({ a: ['c', 'd'] }, { encodeValuesOnly: true })).toBe('a[0]=c&a[1]=d'); + }); + + test('array with multiple items with a comma inside', function () { + // s2t.equal( + // stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), + // 'a=c%2Cd,e', + // ); + // s2t.equal(stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' }), 'a=c%2Cd%2Ce'); + expect(stringify({ a: ['c,d', 'e'] }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe( + 'a=c%2Cd,e', + ); + expect(stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma' })).toBe('a=c%2Cd%2Ce'); + + // s2t.equal( + // stringify( + // { a: ['c,d', 'e'] }, + // { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }, + // ), + // 'a=c%2Cd,e', + // ); + // s2t.equal( + // stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma', commaRoundTrip: true }), + // 'a=c%2Cd%2Ce', + // ); + expect( + stringify( + { a: ['c,d', 'e'] }, + { encodeValuesOnly: true, arrayFormat: 'comma', commaRoundTrip: true }, + ), + ).toBe('a=c%2Cd,e'); + expect(stringify({ a: ['c,d', 'e'] }, { arrayFormat: 'comma', commaRoundTrip: true })).toBe( + 'a=c%2Cd%2Ce', + ); + }); + }); + + test('stringifies a nested array value', function () { + expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe( + 'a[b][0]=c&a[b][1]=d', + ); + expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe( + 'a[b][]=c&a[b][]=d', + ); + expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true, arrayFormat: 'comma' })).toBe( + 'a[b]=c,d', + ); + expect(stringify({ a: { b: ['c', 'd'] } }, { encodeValuesOnly: true })).toBe('a[b][0]=c&a[b][1]=d'); + }); + + test('stringifies comma and empty array values', function () { + // st.equal( + // stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'indices' }), + // 'a[0]=,&a[1]=&a[2]=c,d%', + // ); + // st.equal( + // stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'brackets' }), + // 'a[]=,&a[]=&a[]=c,d%', + // ); + // st.equal( + // stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'comma' }), + // 'a=,,,c,d%', + // ); + // st.equal( + // stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'repeat' }), + // 'a=,&a=&a=c,d%', + // ); + expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'indices' })).toBe( + 'a[0]=,&a[1]=&a[2]=c,d%', + ); + expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'brackets' })).toBe( + 'a[]=,&a[]=&a[]=c,d%', + ); + expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'comma' })).toBe('a=,,,c,d%'); + expect(stringify({ a: [',', '', 'c,d%'] }, { encode: false, arrayFormat: 'repeat' })).toBe( + 'a=,&a=&a=c,d%', + ); + + // st.equal( + // stringify( + // { a: [',', '', 'c,d%'] }, + // { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' }, + // ), + // 'a[0]=%2C&a[1]=&a[2]=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: [',', '', 'c,d%'] }, + // { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }, + // ), + // 'a[]=%2C&a[]=&a[]=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: [',', '', 'c,d%'] }, + // { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }, + // ), + // 'a=%2C,,c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: [',', '', 'c,d%'] }, + // { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' }, + // ), + // 'a=%2C&a=&a=c%2Cd%25', + // ); + expect( + stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }), + ).toBe('a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25'); + expect( + stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }), + ).toBe('a[]=%2C&a[]=&a[]=c%2Cd%25'); + expect( + stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }), + ).toBe('a=%2C%2C%2Cc%2Cd%25'); + expect( + stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }), + ).toBe('a=%2C&a=&a=c%2Cd%25'); + + // st.equal( + // stringify( + // { a: [',', '', 'c,d%'] }, + // { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }, + // ), + // 'a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: [',', '', 'c,d%'] }, + // { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' }, + // ), + // 'a%5B%5D=%2C&a%5B%5D=&a%5B%5D=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: [',', '', 'c,d%'] }, + // { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }, + // ), + // 'a=%2C%2C%2Cc%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: [',', '', 'c,d%'] }, + // { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }, + // ), + // 'a=%2C&a=&a=c%2Cd%25', + // ); + expect( + stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }), + ).toBe('a=%2C&a=&a=c%2Cd%25'); + expect( + stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }), + ).toBe('a%5B0%5D=%2C&a%5B1%5D=&a%5B2%5D=c%2Cd%25'); + expect( + stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }), + ).toBe('a[]=%2C&a[]=&a[]=c%2Cd%25'); + expect( + stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }), + ).toBe('a=%2C%2C%2Cc%2Cd%25'); + expect( + stringify({ a: [',', '', 'c,d%'] }, { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }), + ).toBe('a=%2C&a=&a=c%2Cd%25'); + }); + + test('stringifies comma and empty non-array values', function () { + // st.equal( + // stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'indices' }), + // 'a=,&b=&c=c,d%', + // ); + // st.equal( + // stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'brackets' }), + // 'a=,&b=&c=c,d%', + // ); + // st.equal( + // stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'comma' }), + // 'a=,&b=&c=c,d%', + // ); + // st.equal( + // stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'repeat' }), + // 'a=,&b=&c=c,d%', + // ); + expect(stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'indices' })).toBe( + 'a=,&b=&c=c,d%', + ); + expect(stringify({ a: ',', b: '', c: 'c,d%' }, { encode: false, arrayFormat: 'brackets' })).toBe( + 'a=,&b=&c=c,d%', + ); + + // st.equal( + // stringify( + // { a: ',', b: '', c: 'c,d%' }, + // { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' }, + // ), + // 'a=%2C&b=&c=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: ',', b: '', c: 'c,d%' }, + // { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }, + // ), + // 'a=%2C&b=&c=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: ',', b: '', c: 'c,d%' }, + // { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }, + // ), + // 'a=%2C&b=&c=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: ',', b: '', c: 'c,d%' }, + // { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' }, + // ), + // 'a=%2C&b=&c=c%2Cd%25', + // ); + expect( + stringify( + { a: ',', b: '', c: 'c,d%' }, + { encode: true, encodeValuesOnly: true, arrayFormat: 'indices' }, + ), + ).toBe('a=%2C&b=&c=c%2Cd%25'); + expect( + stringify( + { a: ',', b: '', c: 'c,d%' }, + { encode: true, encodeValuesOnly: true, arrayFormat: 'brackets' }, + ), + ).toBe('a=%2C&b=&c=c%2Cd%25'); + expect( + stringify({ a: ',', b: '', c: 'c,d%' }, { encode: true, encodeValuesOnly: true, arrayFormat: 'comma' }), + ).toBe('a=%2C&b=&c=c%2Cd%25'); + expect( + stringify( + { a: ',', b: '', c: 'c,d%' }, + { encode: true, encodeValuesOnly: true, arrayFormat: 'repeat' }, + ), + ).toBe('a=%2C&b=&c=c%2Cd%25'); + + // st.equal( + // stringify( + // { a: ',', b: '', c: 'c,d%' }, + // { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }, + // ), + // 'a=%2C&b=&c=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: ',', b: '', c: 'c,d%' }, + // { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' }, + // ), + // 'a=%2C&b=&c=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: ',', b: '', c: 'c,d%' }, + // { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }, + // ), + // 'a=%2C&b=&c=c%2Cd%25', + // ); + // st.equal( + // stringify( + // { a: ',', b: '', c: 'c,d%' }, + // { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }, + // ), + // 'a=%2C&b=&c=c%2Cd%25', + // ); + expect( + stringify( + { a: ',', b: '', c: 'c,d%' }, + { encode: true, encodeValuesOnly: false, arrayFormat: 'indices' }, + ), + ).toBe('a=%2C&b=&c=c%2Cd%25'); + expect( + stringify( + { a: ',', b: '', c: 'c,d%' }, + { encode: true, encodeValuesOnly: false, arrayFormat: 'brackets' }, + ), + ).toBe('a=%2C&b=&c=c%2Cd%25'); + expect( + stringify( + { a: ',', b: '', c: 'c,d%' }, + { encode: true, encodeValuesOnly: false, arrayFormat: 'comma' }, + ), + ).toBe('a=%2C&b=&c=c%2Cd%25'); + expect( + stringify( + { a: ',', b: '', c: 'c,d%' }, + { encode: true, encodeValuesOnly: false, arrayFormat: 'repeat' }, + ), + ).toBe('a=%2C&b=&c=c%2Cd%25'); + }); + + test('stringifies a nested array value with dots notation', function () { + // st.equal( + // stringify( + // { a: { b: ['c', 'd'] } }, + // { allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' }, + // ), + // 'a.b[0]=c&a.b[1]=d', + // 'indices: stringifies with dots + indices', + // ); + // st.equal( + // stringify( + // { a: { b: ['c', 'd'] } }, + // { allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' }, + // ), + // 'a.b[]=c&a.b[]=d', + // 'brackets: stringifies with dots + brackets', + // ); + // st.equal( + // stringify( + // { a: { b: ['c', 'd'] } }, + // { allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' }, + // ), + // 'a.b=c,d', + // 'comma: stringifies with dots + comma', + // ); + // st.equal( + // stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encodeValuesOnly: true }), + // 'a.b[0]=c&a.b[1]=d', + // 'default: stringifies with dots + indices', + // ); + expect( + stringify( + { a: { b: ['c', 'd'] } }, + { allowDots: true, encodeValuesOnly: true, arrayFormat: 'indices' }, + ), + ).toBe('a.b[0]=c&a.b[1]=d'); + expect( + stringify( + { a: { b: ['c', 'd'] } }, + { allowDots: true, encodeValuesOnly: true, arrayFormat: 'brackets' }, + ), + ).toBe('a.b[]=c&a.b[]=d'); + expect( + stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encodeValuesOnly: true, arrayFormat: 'comma' }), + ).toBe('a.b=c,d'); + expect(stringify({ a: { b: ['c', 'd'] } }, { allowDots: true, encodeValuesOnly: true })).toBe( + 'a.b[0]=c&a.b[1]=d', + ); + }); + + test('stringifies an object inside an array', function () { + // st.equal( + // stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices', encodeValuesOnly: true }), + // 'a[0][b]=c', + // 'indices => indices', + // ); + // st.equal( + // stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }), + // 'a[b]=c', + // 'repeat => repeat', + // ); + // st.equal( + // stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }), + // 'a[][b]=c', + // 'brackets => brackets', + // ); + // st.equal( + // stringify({ a: [{ b: 'c' }] }, { encodeValuesOnly: true }), + // 'a[0][b]=c', + // 'default => indices', + // ); + expect(stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'indices', encodeValuesOnly: true })).toBe( + 'a[0][b]=c', + ); + expect(stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'repeat', encodeValuesOnly: true })).toBe('a[b]=c'); + expect(stringify({ a: [{ b: 'c' }] }, { arrayFormat: 'brackets', encodeValuesOnly: true })).toBe( + 'a[][b]=c', + ); + expect(stringify({ a: [{ b: 'c' }] }, { encodeValuesOnly: true })).toBe('a[0][b]=c'); + + // st.equal( + // stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices', encodeValuesOnly: true }), + // 'a[0][b][c][0]=1', + // 'indices => indices', + // ); + // st.equal( + // stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'repeat', encodeValuesOnly: true }), + // 'a[b][c]=1', + // 'repeat => repeat', + // ); + // st.equal( + // stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets', encodeValuesOnly: true }), + // 'a[][b][c][]=1', + // 'brackets => brackets', + // ); + // st.equal( + // stringify({ a: [{ b: { c: [1] } }] }, { encodeValuesOnly: true }), + // 'a[0][b][c][0]=1', + // 'default => indices', + // ); + expect(stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'indices', encodeValuesOnly: true })).toBe( + 'a[0][b][c][0]=1', + ); + expect(stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'repeat', encodeValuesOnly: true })).toBe( + 'a[b][c]=1', + ); + expect(stringify({ a: [{ b: { c: [1] } }] }, { arrayFormat: 'brackets', encodeValuesOnly: true })).toBe( + 'a[][b][c][]=1', + ); + expect(stringify({ a: [{ b: { c: [1] } }] }, { encodeValuesOnly: true })).toBe('a[0][b][c][0]=1'); + }); + + test('stringifies an array with mixed objects and primitives', function () { + // st.equal( + // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), + // 'a[0][b]=1&a[1]=2&a[2]=3', + // 'indices => indices', + // ); + // st.equal( + // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + // 'a[][b]=1&a[]=2&a[]=3', + // 'brackets => brackets', + // ); + // st.equal( + // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), + // '???', + // 'brackets => brackets', + // { skip: 'TODO: figure out what this should do' }, + // ); + // st.equal( + // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true }), + // 'a[0][b]=1&a[1]=2&a[2]=3', + // 'default => indices', + // ); + expect(stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe( + 'a[0][b]=1&a[1]=2&a[2]=3', + ); + expect(stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe( + 'a[][b]=1&a[]=2&a[]=3', + ); + // !Skipped: Figure out what this should do + // expect( + // stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true, arrayFormat: 'comma' }), + // ).toBe('???'); + expect(stringify({ a: [{ b: 1 }, 2, 3] }, { encodeValuesOnly: true })).toBe('a[0][b]=1&a[1]=2&a[2]=3'); + }); + + test('stringifies an object inside an array with dots notation', function () { + // st.equal( + // stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false, arrayFormat: 'indices' }), + // 'a[0].b=c', + // 'indices => indices', + // ); + // st.equal( + // stringify( + // { a: [{ b: 'c' }] }, + // { allowDots: true, encode: false, arrayFormat: 'brackets' }, + // ), + // 'a[].b=c', + // 'brackets => brackets', + // ); + // st.equal( + // stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false }), + // 'a[0].b=c', + // 'default => indices', + // ); + expect(stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false, arrayFormat: 'indices' })).toBe( + 'a[0].b=c', + ); + expect(stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false, arrayFormat: 'brackets' })).toBe( + 'a[].b=c', + ); + expect(stringify({ a: [{ b: 'c' }] }, { allowDots: true, encode: false })).toBe('a[0].b=c'); + + // st.equal( + // stringify( + // { a: [{ b: { c: [1] } }] }, + // { allowDots: true, encode: false, arrayFormat: 'indices' }, + // ), + // 'a[0].b.c[0]=1', + // 'indices => indices', + // ); + // st.equal( + // stringify( + // { a: [{ b: { c: [1] } }] }, + // { allowDots: true, encode: false, arrayFormat: 'brackets' }, + // ), + // 'a[].b.c[]=1', + // 'brackets => brackets', + // ); + // st.equal( + // stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false }), + // 'a[0].b.c[0]=1', + // 'default => indices', + // ); + expect( + stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false, arrayFormat: 'indices' }), + ).toBe('a[0].b.c[0]=1'); + expect( + stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false, arrayFormat: 'brackets' }), + ).toBe('a[].b.c[]=1'); + expect(stringify({ a: [{ b: { c: [1] } }] }, { allowDots: true, encode: false })).toBe('a[0].b.c[0]=1'); + }); + + test('does not omit object keys when indices = false', function () { + // st.equal(stringify({ a: [{ b: 'c' }] }, { indices: false }), 'a%5Bb%5D=c'); + expect(stringify({ a: [{ b: 'c' }] }, { indices: false })).toBe('a%5Bb%5D=c'); + }); + + test('uses indices notation for arrays when indices=true', function () { + // st.equal(stringify({ a: ['b', 'c'] }, { indices: true }), 'a%5B0%5D=b&a%5B1%5D=c'); + expect(stringify({ a: ['b', 'c'] }, { indices: true })).toBe('a%5B0%5D=b&a%5B1%5D=c'); + }); + + test('uses indices notation for arrays when no arrayFormat is specified', function () { + // st.equal(stringify({ a: ['b', 'c'] }), 'a%5B0%5D=b&a%5B1%5D=c'); + expect(stringify({ a: ['b', 'c'] })).toBe('a%5B0%5D=b&a%5B1%5D=c'); + }); + + test('uses indices notation for arrays when arrayFormat=indices', function () { + // st.equal(stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' }), 'a%5B0%5D=b&a%5B1%5D=c'); + expect(stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })).toBe('a%5B0%5D=b&a%5B1%5D=c'); + }); + + test('uses repeat notation for arrays when arrayFormat=repeat', function () { + // st.equal(stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' }), 'a=b&a=c'); + expect(stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })).toBe('a=b&a=c'); + }); + + test('uses brackets notation for arrays when arrayFormat=brackets', function () { + // st.equal(stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' }), 'a%5B%5D=b&a%5B%5D=c'); + expect(stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })).toBe('a%5B%5D=b&a%5B%5D=c'); + }); + + test('stringifies a complicated object', function () { + // st.equal(stringify({ a: { b: 'c', d: 'e' } }), 'a%5Bb%5D=c&a%5Bd%5D=e'); + expect(stringify({ a: { b: 'c', d: 'e' } })).toBe('a%5Bb%5D=c&a%5Bd%5D=e'); + }); + + test('stringifies an empty value', function () { + // st.equal(stringify({ a: '' }), 'a='); + // st.equal(stringify({ a: null }, { strictNullHandling: true }), 'a'); + expect(stringify({ a: '' })).toBe('a='); + expect(stringify({ a: null }, { strictNullHandling: true })).toBe('a'); + + // st.equal(stringify({ a: '', b: '' }), 'a=&b='); + // st.equal(stringify({ a: null, b: '' }, { strictNullHandling: true }), 'a&b='); + expect(stringify({ a: '', b: '' })).toBe('a=&b='); + expect(stringify({ a: null, b: '' }, { strictNullHandling: true })).toBe('a&b='); + + // st.equal(stringify({ a: { b: '' } }), 'a%5Bb%5D='); + // st.equal(stringify({ a: { b: null } }, { strictNullHandling: true }), 'a%5Bb%5D'); + // st.equal(stringify({ a: { b: null } }, { strictNullHandling: false }), 'a%5Bb%5D='); + expect(stringify({ a: { b: '' } })).toBe('a%5Bb%5D='); + expect(stringify({ a: { b: null } }, { strictNullHandling: true })).toBe('a%5Bb%5D'); + expect(stringify({ a: { b: null } }, { strictNullHandling: false })).toBe('a%5Bb%5D='); + }); + + test('stringifies an empty array in different arrayFormat', function () { + // st.equal(stringify({ a: [], b: [null], c: 'c' }, { encode: false }), 'b[0]=&c=c'); + expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false })).toBe('b[0]=&c=c'); + // arrayFormat default + // st.equal( + // stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices' }), + // 'b[0]=&c=c', + // ); + // st.equal( + // stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets' }), + // 'b[]=&c=c', + // ); + // st.equal( + // stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat' }), + // 'b=&c=c', + // ); + // st.equal( + // stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' }), + // 'b=&c=c', + // ); + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'comma', commaRoundTrip: true }, + // ), + // 'b[]=&c=c', + // ); + expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices' })).toBe( + 'b[0]=&c=c', + ); + expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets' })).toBe( + 'b[]=&c=c', + ); + expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat' })).toBe('b=&c=c'); + expect(stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma' })).toBe('b=&c=c'); + expect( + stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', commaRoundTrip: true }), + ).toBe('b[]=&c=c'); + + // with strictNullHandling + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'indices', strictNullHandling: true }, + // ), + // 'b[0]&c=c', + // ); + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'brackets', strictNullHandling: true }, + // ), + // 'b[]&c=c', + // ); + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'repeat', strictNullHandling: true }, + // ), + // 'b&c=c', + // ); + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'comma', strictNullHandling: true }, + // ), + // 'b&c=c', + // ); + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'comma', strictNullHandling: true, commaRoundTrip: true }, + // ), + // 'b[]&c=c', + // ); + + expect( + stringify( + { a: [], b: [null], c: 'c' }, + { encode: false, arrayFormat: 'indices', strictNullHandling: true }, + ), + ).toBe('b[0]&c=c'); + expect( + stringify( + { a: [], b: [null], c: 'c' }, + { encode: false, arrayFormat: 'brackets', strictNullHandling: true }, + ), + ).toBe('b[]&c=c'); + expect( + stringify( + { a: [], b: [null], c: 'c' }, + { encode: false, arrayFormat: 'repeat', strictNullHandling: true }, + ), + ).toBe('b&c=c'); + expect( + stringify( + { a: [], b: [null], c: 'c' }, + { encode: false, arrayFormat: 'comma', strictNullHandling: true }, + ), + ).toBe('b&c=c'); + expect( + stringify( + { a: [], b: [null], c: 'c' }, + { encode: false, arrayFormat: 'comma', strictNullHandling: true, commaRoundTrip: true }, + ), + ).toBe('b[]&c=c'); + + // with skipNulls + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'indices', skipNulls: true }, + // ), + // 'c=c', + // ); + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'brackets', skipNulls: true }, + // ), + // 'c=c', + // ); + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'repeat', skipNulls: true }, + // ), + // 'c=c', + // ); + // st.equal( + // stringify( + // { a: [], b: [null], c: 'c' }, + // { encode: false, arrayFormat: 'comma', skipNulls: true }, + // ), + // 'c=c', + // ); + expect( + stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'indices', skipNulls: true }), + ).toBe('c=c'); + expect( + stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'brackets', skipNulls: true }), + ).toBe('c=c'); + expect( + stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'repeat', skipNulls: true }), + ).toBe('c=c'); + expect( + stringify({ a: [], b: [null], c: 'c' }, { encode: false, arrayFormat: 'comma', skipNulls: true }), + ).toBe('c=c'); + }); + + test('stringifies a null object', function () { + var obj = Object.create(null); + obj.a = 'b'; + // st.equal(stringify(obj), 'a=b'); + expect(stringify(obj)).toBe('a=b'); + }); + + test('returns an empty string for invalid input', function () { + // st.equal(stringify(undefined), ''); + // st.equal(stringify(false), ''); + // st.equal(stringify(null), ''); + // st.equal(stringify(''), ''); + expect(stringify(undefined)).toBe(''); + expect(stringify(false)).toBe(''); + expect(stringify(null)).toBe(''); + expect(stringify('')).toBe(''); + }); + + test('stringifies an object with a null object as a child', function () { + var obj = { a: Object.create(null) }; + + obj.a.b = 'c'; + // st.equal(stringify(obj), 'a%5Bb%5D=c'); + expect(stringify(obj)).toBe('a%5Bb%5D=c'); + }); + + test('drops keys with a value of undefined', function () { + // st.equal(stringify({ a: undefined }), ''); + expect(stringify({ a: undefined })).toBe(''); + + // st.equal( + // stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true }), + // 'a%5Bc%5D', + // ); + // st.equal( + // stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false }), + // 'a%5Bc%5D=', + // ); + // st.equal(stringify({ a: { b: undefined, c: '' } }), 'a%5Bc%5D='); + expect(stringify({ a: { b: undefined, c: null } }, { strictNullHandling: true })).toBe('a%5Bc%5D'); + expect(stringify({ a: { b: undefined, c: null } }, { strictNullHandling: false })).toBe('a%5Bc%5D='); + expect(stringify({ a: { b: undefined, c: '' } })).toBe('a%5Bc%5D='); + }); + + test('url encodes values', function () { + // st.equal(stringify({ a: 'b c' }), 'a=b%20c'); + expect(stringify({ a: 'b c' })).toBe('a=b%20c'); + }); + + test('stringifies a date', function () { + var now = new Date(); + var str = 'a=' + encodeURIComponent(now.toISOString()); + // st.equal(stringify({ a: now }), str); + expect(stringify({ a: now })).toBe(str); + }); + + test('stringifies the weird object from qs', function () { + // st.equal( + // stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' }), + // 'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F', + // ); + expect(stringify({ 'my weird field': '~q1!2"\'w$5&7/z8)?' })).toBe( + 'my%20weird%20field=~q1%212%22%27w%245%267%2Fz8%29%3F', + ); + }); + + // TODO: Investigate how to to intercept in vitest + // TODO(rob) + test('skips properties that are part of the object prototype', function () { + // st.intercept(Object.prototype, 'crash', { value: 'test' }); + // @ts-expect-error + Object.prototype.crash = 'test'; + + // st.equal(stringify({ a: 'b' }), 'a=b'); + // st.equal(stringify({ a: { b: 'c' } }), 'a%5Bb%5D=c'); + expect(stringify({ a: 'b' })).toBe('a=b'); + expect(stringify({ a: { b: 'c' } })).toBe('a%5Bb%5D=c'); + }); + + test('stringifies boolean values', function () { + // st.equal(stringify({ a: true }), 'a=true'); + // st.equal(stringify({ a: { b: true } }), 'a%5Bb%5D=true'); + // st.equal(stringify({ b: false }), 'b=false'); + // st.equal(stringify({ b: { c: false } }), 'b%5Bc%5D=false'); + expect(stringify({ a: true })).toBe('a=true'); + expect(stringify({ a: { b: true } })).toBe('a%5Bb%5D=true'); + expect(stringify({ b: false })).toBe('b=false'); + expect(stringify({ b: { c: false } })).toBe('b%5Bc%5D=false'); + }); + + test('stringifies buffer values', function () { + // st.equal(stringify({ a: Buffer.from('test') }), 'a=test'); + // st.equal(stringify({ a: { b: Buffer.from('test') } }), 'a%5Bb%5D=test'); + }); + + test('stringifies an object using an alternative delimiter', function () { + // st.equal(stringify({ a: 'b', c: 'd' }, { delimiter: ';' }), 'a=b;c=d'); + expect(stringify({ a: 'b', c: 'd' }, { delimiter: ';' })).toBe('a=b;c=d'); + }); + + // We dont target environments which dont even have Buffer + // test('does not blow up when Buffer global is missing', function () { + // var restore = mockProperty(global, 'Buffer', { delete: true }); + + // var result = stringify({ a: 'b', c: 'd' }); + + // restore(); + + // st.equal(result, 'a=b&c=d'); + // st.end(); + // }); + + test('does not crash when parsing circular references', function () { + var a: any = {}; + a.b = a; + + // st['throws']( + // function () { + // stringify({ 'foo[bar]': 'baz', 'foo[baz]': a }); + // }, + // /RangeError: Cyclic object value/, + // 'cyclic values throw', + // ); + expect(() => { + stringify({ 'foo[bar]': 'baz', 'foo[baz]': a }); + }).toThrow('Cyclic object value'); + + var circular: any = { + a: 'value', + }; + circular.a = circular; + // st['throws']( + // function () { + // stringify(circular); + // }, + // /RangeError: Cyclic object value/, + // 'cyclic values throw', + // ); + expect(() => { + stringify(circular); + }).toThrow('Cyclic object value'); + + var arr = ['a']; + // st.doesNotThrow(function () { + // stringify({ x: arr, y: arr }); + // }, 'non-cyclic values do not throw'); + expect(() => { + stringify({ x: arr, y: arr }); + }).not.toThrow(); + }); + + test('non-circular duplicated references can still work', function () { + var hourOfDay = { + function: 'hour_of_day', + }; + + var p1 = { + function: 'gte', + arguments: [hourOfDay, 0], + }; + var p2 = { + function: 'lte', + arguments: [hourOfDay, 23], + }; + + // st.equal( + // stringify( + // { filters: { $and: [p1, p2] } }, + // { encodeValuesOnly: true, arrayFormat: 'indices' }, + // ), + // 'filters[$and][0][function]=gte&filters[$and][0][arguments][0][function]=hour_of_day&filters[$and][0][arguments][1]=0&filters[$and][1][function]=lte&filters[$and][1][arguments][0][function]=hour_of_day&filters[$and][1][arguments][1]=23', + // ); + // st.equal( + // stringify( + // { filters: { $and: [p1, p2] } }, + // { encodeValuesOnly: true, arrayFormat: 'brackets' }, + // ), + // 'filters[$and][][function]=gte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=0&filters[$and][][function]=lte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=23', + // ); + // st.equal( + // stringify( + // { filters: { $and: [p1, p2] } }, + // { encodeValuesOnly: true, arrayFormat: 'repeat' }, + // ), + // 'filters[$and][function]=gte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=0&filters[$and][function]=lte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=23', + // ); + expect( + stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'indices' }), + ).toBe( + 'filters[$and][0][function]=gte&filters[$and][0][arguments][0][function]=hour_of_day&filters[$and][0][arguments][1]=0&filters[$and][1][function]=lte&filters[$and][1][arguments][0][function]=hour_of_day&filters[$and][1][arguments][1]=23', + ); + expect( + stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + ).toBe( + 'filters[$and][][function]=gte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=0&filters[$and][][function]=lte&filters[$and][][arguments][][function]=hour_of_day&filters[$and][][arguments][]=23', + ); + expect( + stringify({ filters: { $and: [p1, p2] } }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), + ).toBe( + 'filters[$and][function]=gte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=0&filters[$and][function]=lte&filters[$and][arguments][function]=hour_of_day&filters[$and][arguments]=23', + ); + }); + + test('selects properties when filter=array', function () { + // st.equal(stringify({ a: 'b' }, { filter: ['a'] }), 'a=b'); + // st.equal(stringify({ a: 1 }, { filter: [] }), ''); + expect(stringify({ a: 'b' }, { filter: ['a'] })).toBe('a=b'); + expect(stringify({ a: 1 }, { filter: [] })).toBe(''); + + // st.equal( + // stringify( + // { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, + // { filter: ['a', 'b', 0, 2], arrayFormat: 'indices' }, + // ), + // 'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3', + // 'indices => indices', + // ); + // st.equal( + // stringify( + // { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, + // { filter: ['a', 'b', 0, 2], arrayFormat: 'brackets' }, + // ), + // 'a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=3', + // 'brackets => brackets', + // ); + // st.equal( + // stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] }), + // 'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3', + // 'default => indices', + // ); + expect(stringify({ a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, { filter: ['a', 'b', 0, 2] })).toBe( + 'a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3', + ); + expect( + stringify( + { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, + { filter: ['a', 'b', 0, 2], arrayFormat: 'indices' }, + ), + ).toBe('a%5Bb%5D%5B0%5D=1&a%5Bb%5D%5B2%5D=3'); + expect( + stringify( + { a: { b: [1, 2, 3, 4], c: 'd' }, c: 'f' }, + { filter: ['a', 'b', 0, 2], arrayFormat: 'brackets' }, + ), + ).toBe('a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=3'); + }); + + test('supports custom representations when filter=function', function () { + var calls = 0; + var obj = { a: 'b', c: 'd', e: { f: new Date(1257894000000) } }; + var filterFunc: StringifyOptions['filter'] = function (prefix, value) { + calls += 1; + if (calls === 1) { + // st.equal(prefix, '', 'prefix is empty'); + // st.equal(value, obj); + expect(prefix).toBe(''); + expect(value).toBe(obj); + } else if (prefix === 'c') { + return void 0; + } else if (value instanceof Date) { + // st.equal(prefix, 'e[f]'); + expect(prefix).toBe('e[f]'); + return value.getTime(); + } + return value; + }; + + // st.equal(stringify(obj, { filter: filterFunc }), 'a=b&e%5Bf%5D=1257894000000'); + // st.equal(calls, 5); + expect(stringify(obj, { filter: filterFunc })).toBe('a=b&e%5Bf%5D=1257894000000'); + expect(calls).toBe(5); + }); + + test('can disable uri encoding', function () { + // st.equal(stringify({ a: 'b' }, { encode: false }), 'a=b'); + // st.equal(stringify({ a: { b: 'c' } }, { encode: false }), 'a[b]=c'); + // st.equal( + // stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false }), + // 'a=b&c', + // ); + expect(stringify({ a: 'b' }, { encode: false })).toBe('a=b'); + expect(stringify({ a: { b: 'c' } }, { encode: false })).toBe('a[b]=c'); + expect(stringify({ a: 'b', c: null }, { strictNullHandling: true, encode: false })).toBe('a=b&c'); + }); + + test('can sort the keys', function () { + // @ts-expect-error + var sort: NonNullable = function (a: string, b: string) { + return a.localeCompare(b); + }; + // st.equal(stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort }), 'a=c&b=f&z=y'); + // st.equal( + // stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort }), + // 'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a', + // ); + expect(stringify({ a: 'c', z: 'y', b: 'f' }, { sort: sort })).toBe('a=c&b=f&z=y'); + expect(stringify({ a: 'c', z: { j: 'a', i: 'b' }, b: 'f' }, { sort: sort })).toBe( + 'a=c&b=f&z%5Bi%5D=b&z%5Bj%5D=a', + ); + }); + + test('can sort the keys at depth 3 or more too', function () { + // @ts-expect-error + var sort: NonNullable = function (a: string, b: string) { + return a.localeCompare(b); + }; + // st.equal( + // stringify( + // { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' }, + // { sort: sort, encode: false }, + // ), + // 'a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb', + // ); + // st.equal( + // stringify( + // { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' }, + // { sort: null, encode: false }, + // ), + // 'a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b', + // ); + expect( + stringify( + { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' }, + { sort: sort, encode: false }, + ), + ).toBe('a=a&b=b&z[zi][zia]=zia&z[zi][zib]=zib&z[zj][zja]=zja&z[zj][zjb]=zjb'); + expect( + stringify( + { a: 'a', z: { zj: { zjb: 'zjb', zja: 'zja' }, zi: { zib: 'zib', zia: 'zia' } }, b: 'b' }, + { sort: null, encode: false }, + ), + ).toBe('a=a&z[zj][zjb]=zjb&z[zj][zja]=zja&z[zi][zib]=zib&z[zi][zia]=zia&b=b'); + }); + + test('can stringify with custom encoding', function () { + // st.equal( + // stringify( + // { 県: '大阪府', '': '' }, + // { + // encoder: function (str) { + // if (str.length === 0) { + // return ''; + // } + // var buf = iconv.encode(str, 'shiftjis'); + // var result = []; + // for (var i = 0; i < buf.length; ++i) { + // result.push(buf.readUInt8(i).toString(16)); + // } + // return '%' + result.join('%'); + // }, + // }, + // ), + // '%8c%a7=%91%e5%8d%e3%95%7b&=', + // ); + expect( + stringify( + { 県: '大阪府', '': '' }, + { + encoder: function (str) { + if (str.length === 0) { + return ''; + } + var buf = iconv.encode(str, 'shiftjis'); + var result = []; + for (var i = 0; i < buf.length; ++i) { + result.push(buf.readUInt8(i).toString(16)); + } + return '%' + result.join('%'); + }, + }, + ), + ).toBe('%8c%a7=%91%e5%8d%e3%95%7b&='); + }); + + test('receives the default encoder as a second argument', function () { + // stringify( + // { a: 1, b: new Date(), c: true, d: [1] }, + // { + // encoder: function (str) { + // st.match(typeof str, /^(?:string|number|boolean)$/); + // return ''; + // }, + // }, + // ); + + stringify( + { a: 1, b: new Date(), c: true, d: [1] }, + { + encoder: function (str) { + // st.match(typeof str, /^(?:string|number|boolean)$/); + assert.match(typeof str, /^(?:string|number|boolean)$/); + return ''; + }, + }, + ); + }); + + test('receives the default encoder as a second argument', function () { + // stringify( + // { a: 1 }, + // { + // encoder: function (str, defaultEncoder) { + // st.equal(defaultEncoder, utils.encode); + // }, + // }, + // ); + + stringify( + { a: 1 }, + { + // @ts-ignore + encoder: function (_str, defaultEncoder) { + expect(defaultEncoder).toBe(encode); + }, + }, + ); + }); + + test('throws error with wrong encoder', function () { + // st['throws'](function () { + // stringify({}, { encoder: 'string' }); + // }, new TypeError('Encoder has to be a function.')); + // st.end(); + expect(() => { + // @ts-expect-error + stringify({}, { encoder: 'string' }); + }).toThrow(TypeError); + }); + + (typeof Buffer === 'undefined' ? test.skip : test)( + 'can use custom encoder for a buffer object', + function () { + // st.equal( + // stringify( + // { a: Buffer.from([1]) }, + // { + // encoder: function (buffer) { + // if (typeof buffer === 'string') { + // return buffer; + // } + // return String.fromCharCode(buffer.readUInt8(0) + 97); + // }, + // }, + // ), + // 'a=b', + // ); + expect( + stringify( + { a: Buffer.from([1]) }, + { + encoder: function (buffer) { + if (typeof buffer === 'string') { + return buffer; + } + return String.fromCharCode(buffer.readUInt8(0) + 97); + }, + }, + ), + ).toBe('a=b'); + + // st.equal( + // stringify( + // { a: Buffer.from('a b') }, + // { + // encoder: function (buffer) { + // return buffer; + // }, + // }, + // ), + // 'a=a b', + // ); + expect( + stringify( + { a: Buffer.from('a b') }, + { + encoder: function (buffer) { + return buffer; + }, + }, + ), + ).toBe('a=a b'); + }, + ); + + test('serializeDate option', function () { + var date = new Date(); + // st.equal( + // stringify({ a: date }), + // 'a=' + date.toISOString().replace(/:/g, '%3A'), + // 'default is toISOString', + // ); + expect(stringify({ a: date })).toBe('a=' + date.toISOString().replace(/:/g, '%3A')); + + var mutatedDate = new Date(); + mutatedDate.toISOString = function () { + throw new SyntaxError(); + }; + // st['throws'](function () { + // mutatedDate.toISOString(); + // }, SyntaxError); + expect(() => { + mutatedDate.toISOString(); + }).toThrow(SyntaxError); + // st.equal( + // stringify({ a: mutatedDate }), + // 'a=' + Date.prototype.toISOString.call(mutatedDate).replace(/:/g, '%3A'), + // 'toISOString works even when method is not locally present', + // ); + expect(stringify({ a: mutatedDate })).toBe( + 'a=' + Date.prototype.toISOString.call(mutatedDate).replace(/:/g, '%3A'), + ); + + var specificDate = new Date(6); + // st.equal( + // stringify( + // { a: specificDate }, + // { + // serializeDate: function (d) { + // return d.getTime() * 7; + // }, + // }, + // ), + // 'a=42', + // 'custom serializeDate function called', + // ); + expect( + stringify( + { a: specificDate }, + { + // @ts-ignore + serializeDate: function (d) { + return d.getTime() * 7; + }, + }, + ), + ).toBe('a=42'); + + // st.equal( + // stringify( + // { a: [date] }, + // { + // serializeDate: function (d) { + // return d.getTime(); + // }, + // arrayFormat: 'comma', + // }, + // ), + // 'a=' + date.getTime(), + // 'works with arrayFormat comma', + // ); + // st.equal( + // stringify( + // { a: [date] }, + // { + // serializeDate: function (d) { + // return d.getTime(); + // }, + // arrayFormat: 'comma', + // commaRoundTrip: true, + // }, + // ), + // 'a%5B%5D=' + date.getTime(), + // 'works with arrayFormat comma', + // ); + expect( + stringify( + { a: [date] }, + { + // @ts-expect-error + serializeDate: function (d) { + return d.getTime(); + }, + arrayFormat: 'comma', + }, + ), + ).toBe('a=' + date.getTime()); + expect( + stringify( + { a: [date] }, + { + // @ts-expect-error + serializeDate: function (d) { + return d.getTime(); + }, + arrayFormat: 'comma', + commaRoundTrip: true, + }, + ), + ).toBe('a%5B%5D=' + date.getTime()); + }); + + test('RFC 1738 serialization', function () { + // st.equal(stringify({ a: 'b c' }, { format: formats.RFC1738 }), 'a=b+c'); + // st.equal(stringify({ 'a b': 'c d' }, { format: formats.RFC1738 }), 'a+b=c+d'); + // st.equal( + // stringify({ 'a b': Buffer.from('a b') }, { format: formats.RFC1738 }), + // 'a+b=a+b', + // ); + expect(stringify({ a: 'b c' }, { format: 'RFC1738' })).toBe('a=b+c'); + expect(stringify({ 'a b': 'c d' }, { format: 'RFC1738' })).toBe('a+b=c+d'); + expect(stringify({ 'a b': Buffer.from('a b') }, { format: 'RFC1738' })).toBe('a+b=a+b'); + + // st.equal(stringify({ 'foo(ref)': 'bar' }, { format: formats.RFC1738 }), 'foo(ref)=bar'); + expect(stringify({ 'foo(ref)': 'bar' }, { format: 'RFC1738' })).toBe('foo(ref)=bar'); + }); + + test('RFC 3986 spaces serialization', function () { + // st.equal(stringify({ a: 'b c' }, { format: formats.RFC3986 }), 'a=b%20c'); + // st.equal(stringify({ 'a b': 'c d' }, { format: formats.RFC3986 }), 'a%20b=c%20d'); + // st.equal( + // stringify({ 'a b': Buffer.from('a b') }, { format: formats.RFC3986 }), + // 'a%20b=a%20b', + // ); + expect(stringify({ a: 'b c' }, { format: 'RFC3986' })).toBe('a=b%20c'); + expect(stringify({ 'a b': 'c d' }, { format: 'RFC3986' })).toBe('a%20b=c%20d'); + expect(stringify({ 'a b': Buffer.from('a b') }, { format: 'RFC3986' })).toBe('a%20b=a%20b'); + }); + + test('Backward compatibility to RFC 3986', function () { + // st.equal(stringify({ a: 'b c' }), 'a=b%20c'); + // st.equal(stringify({ 'a b': Buffer.from('a b') }), 'a%20b=a%20b'); + expect(stringify({ a: 'b c' })).toBe('a=b%20c'); + expect(stringify({ 'a b': Buffer.from('a b') })).toBe('a%20b=a%20b'); + }); + + test('Edge cases and unknown formats', function () { + ['UFO1234', false, 1234, null, {}, []].forEach(function (format) { + // st['throws'](function () { + // stringify({ a: 'b c' }, { format: format }); + // }, new TypeError('Unknown format option provided.')); + expect(() => { + // @ts-expect-error + stringify({ a: 'b c' }, { format: format }); + }).toThrow(TypeError); + }); + }); + + test('encodeValuesOnly', function () { + // st.equal( + // stringify( + // { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, + // { encodeValuesOnly: true, arrayFormat: 'indices' }, + // ), + // 'a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h', + // 'encodeValuesOnly + indices', + // ); + // st.equal( + // stringify( + // { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, + // { encodeValuesOnly: true, arrayFormat: 'brackets' }, + // ), + // 'a=b&c[]=d&c[]=e%3Df&f[][]=g&f[][]=h', + // 'encodeValuesOnly + brackets', + // ); + // st.equal( + // stringify( + // { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, + // { encodeValuesOnly: true, arrayFormat: 'repeat' }, + // ), + // 'a=b&c=d&c=e%3Df&f=g&f=h', + // 'encodeValuesOnly + repeat', + // ); + expect( + stringify( + { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, + { encodeValuesOnly: true, arrayFormat: 'indices' }, + ), + ).toBe('a=b&c[0]=d&c[1]=e%3Df&f[0][0]=g&f[1][0]=h'); + expect( + stringify( + { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, + { encodeValuesOnly: true, arrayFormat: 'brackets' }, + ), + ).toBe('a=b&c[]=d&c[]=e%3Df&f[][]=g&f[][]=h'); + expect( + stringify( + { a: 'b', c: ['d', 'e=f'], f: [['g'], ['h']] }, + { encodeValuesOnly: true, arrayFormat: 'repeat' }, + ), + ).toBe('a=b&c=d&c=e%3Df&f=g&f=h'); + + // st.equal( + // stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'indices' }), + // 'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h', + // 'no encodeValuesOnly + indices', + // ); + // st.equal( + // stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'brackets' }), + // 'a=b&c%5B%5D=d&c%5B%5D=e&f%5B%5D%5B%5D=g&f%5B%5D%5B%5D=h', + // 'no encodeValuesOnly + brackets', + // ); + // st.equal( + // stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'repeat' }), + // 'a=b&c=d&c=e&f=g&f=h', + // 'no encodeValuesOnly + repeat', + // ); + expect(stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'indices' })).toBe( + 'a=b&c%5B0%5D=d&c%5B1%5D=e&f%5B0%5D%5B0%5D=g&f%5B1%5D%5B0%5D=h', + ); + expect(stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'brackets' })).toBe( + 'a=b&c%5B%5D=d&c%5B%5D=e&f%5B%5D%5B%5D=g&f%5B%5D%5B%5D=h', + ); + expect(stringify({ a: 'b', c: ['d', 'e'], f: [['g'], ['h']] }, { arrayFormat: 'repeat' })).toBe( + 'a=b&c=d&c=e&f=g&f=h', + ); + }); + + test('encodeValuesOnly - strictNullHandling', function () { + // st.equal( + // stringify({ a: { b: null } }, { encodeValuesOnly: true, strictNullHandling: true }), + // 'a[b]', + // ); + expect(stringify({ a: { b: null } }, { encodeValuesOnly: true, strictNullHandling: true })).toBe('a[b]'); + }); + + test('throws if an invalid charset is specified', function () { + // st['throws'](function () { + // stringify({ a: 'b' }, { charset: 'foobar' }); + // }, new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined')); + expect(() => { + // @ts-expect-error + stringify({ a: 'b' }, { charset: 'foobar' }); + }).toThrow(TypeError); + }); + + test('respects a charset of iso-8859-1', function () { + // st.equal(stringify({ æ: 'æ' }, { charset: 'iso-8859-1' }), '%E6=%E6'); + expect(stringify({ æ: 'æ' }, { charset: 'iso-8859-1' })).toBe('%E6=%E6'); + }); + + test('encodes unrepresentable chars as numeric entities in iso-8859-1 mode', function () { + // st.equal(stringify({ a: '☺' }, { charset: 'iso-8859-1' }), 'a=%26%239786%3B'); + expect(stringify({ a: '☺' }, { charset: 'iso-8859-1' })).toBe('a=%26%239786%3B'); + }); + + test('respects an explicit charset of utf-8 (the default)', function () { + // st.equal(stringify({ a: 'æ' }, { charset: 'utf-8' }), 'a=%C3%A6'); + expect(stringify({ a: 'æ' }, { charset: 'utf-8' })).toBe('a=%C3%A6'); + }); + + test('`charsetSentinel` option', function () { + // st.equal( + // stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' }), + // 'utf8=%E2%9C%93&a=%C3%A6', + // 'adds the right sentinel when instructed to and the charset is utf-8', + // ); + expect(stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'utf-8' })).toBe( + 'utf8=%E2%9C%93&a=%C3%A6', + ); + + // st.equal( + // stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' }), + // 'utf8=%26%2310003%3B&a=%E6', + // 'adds the right sentinel when instructed to and the charset is iso-8859-1', + // ); + expect(stringify({ a: 'æ' }, { charsetSentinel: true, charset: 'iso-8859-1' })).toBe( + 'utf8=%26%2310003%3B&a=%E6', + ); + }); + + test('does not mutate the options argument', function () { + var options = {}; + stringify({}, options); + // st.deepEqual(options, {}); + expect(options).toEqual({}); + }); + + test('strictNullHandling works with custom filter', function () { + // @ts-expect-error + var filter = function (_prefix, value) { + return value; + }; + + var options = { strictNullHandling: true, filter: filter }; + // st.equal(stringify({ key: null }, options), 'key'); + expect(stringify({ key: null }, options)).toBe('key'); + }); + + test('strictNullHandling works with null serializeDate', function () { + var serializeDate = function () { + return null; + }; + var options = { strictNullHandling: true, serializeDate: serializeDate }; + var date = new Date(); + // st.equal(stringify({ key: date }, options), 'key'); + // @ts-expect-error + expect(stringify({ key: date }, options)).toBe('key'); + }); + + test('allows for encoding keys and values differently', function () { + // @ts-expect-error + var encoder = function (str, defaultEncoder, charset, type) { + if (type === 'key') { + return defaultEncoder(str, defaultEncoder, charset, type).toLowerCase(); + } + if (type === 'value') { + return defaultEncoder(str, defaultEncoder, charset, type).toUpperCase(); + } + throw 'this should never happen! type: ' + type; + }; + + // st.deepEqual(stringify({ KeY: 'vAlUe' }, { encoder: encoder }), 'key=VALUE'); + expect(stringify({ KeY: 'vAlUe' }, { encoder: encoder })).toBe('key=VALUE'); + }); + + test('objects inside arrays', function () { + var obj = { a: { b: { c: 'd', e: 'f' } } }; + var withArray = { a: { b: [{ c: 'd', e: 'f' }] } }; + + // st.equal( + // stringify(obj, { encode: false }), + // 'a[b][c]=d&a[b][e]=f', + // 'no array, no arrayFormat', + // ); + // st.equal( + // stringify(obj, { encode: false, arrayFormat: 'brackets' }), + // 'a[b][c]=d&a[b][e]=f', + // 'no array, bracket', + // ); + // st.equal( + // stringify(obj, { encode: false, arrayFormat: 'indices' }), + // 'a[b][c]=d&a[b][e]=f', + // 'no array, indices', + // ); + // st.equal( + // stringify(obj, { encode: false, arrayFormat: 'repeat' }), + // 'a[b][c]=d&a[b][e]=f', + // 'no array, repeat', + // ); + // st.equal( + // stringify(obj, { encode: false, arrayFormat: 'comma' }), + // 'a[b][c]=d&a[b][e]=f', + // 'no array, comma', + // ); + expect(stringify(obj, { encode: false })).toBe('a[b][c]=d&a[b][e]=f'); + expect(stringify(obj, { encode: false, arrayFormat: 'brackets' })).toBe('a[b][c]=d&a[b][e]=f'); + expect(stringify(obj, { encode: false, arrayFormat: 'indices' })).toBe('a[b][c]=d&a[b][e]=f'); + expect(stringify(obj, { encode: false, arrayFormat: 'repeat' })).toBe('a[b][c]=d&a[b][e]=f'); + expect(stringify(obj, { encode: false, arrayFormat: 'comma' })).toBe('a[b][c]=d&a[b][e]=f'); + + // st.equal( + // stringify(withArray, { encode: false }), + // 'a[b][0][c]=d&a[b][0][e]=f', + // 'array, no arrayFormat', + // ); + // st.equal( + // stringify(withArray, { encode: false, arrayFormat: 'brackets' }), + // 'a[b][][c]=d&a[b][][e]=f', + // 'array, bracket', + // ); + // st.equal( + // stringify(withArray, { encode: false, arrayFormat: 'indices' }), + // 'a[b][0][c]=d&a[b][0][e]=f', + // 'array, indices', + // ); + // st.equal( + // stringify(withArray, { encode: false, arrayFormat: 'repeat' }), + // 'a[b][c]=d&a[b][e]=f', + // 'array, repeat', + // ); + // st.equal( + // stringify(withArray, { encode: false, arrayFormat: 'comma' }), + // '???', + // 'array, comma', + // { skip: 'TODO: figure out what this should do' }, + // ); + expect(stringify(withArray, { encode: false })).toBe('a[b][0][c]=d&a[b][0][e]=f'); + expect(stringify(withArray, { encode: false, arrayFormat: 'brackets' })).toBe('a[b][][c]=d&a[b][][e]=f'); + expect(stringify(withArray, { encode: false, arrayFormat: 'indices' })).toBe('a[b][0][c]=d&a[b][0][e]=f'); + expect(stringify(withArray, { encode: false, arrayFormat: 'repeat' })).toBe('a[b][c]=d&a[b][e]=f'); + // !TODo: Figure out what this should do + // expect(stringify(withArray, { encode: false, arrayFormat: 'comma' })).toBe( + // 'a[b][c]=d&a[b][e]=f', + // ); + }); + + test('stringifies sparse arrays', function () { + // st.equal( + // stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), + // 'a[1]=2&a[4]=1', + // ); + // st.equal( + // stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + // 'a[]=2&a[]=1', + // ); + // st.equal( + // stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), + // 'a=2&a=1', + // ); + expect(stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'indices' })).toBe( + 'a[1]=2&a[4]=1', + ); + expect(stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'brackets' })).toBe( + 'a[]=2&a[]=1', + ); + expect(stringify({ a: [, '2', , , '1'] }, { encodeValuesOnly: true, arrayFormat: 'repeat' })).toBe( + 'a=2&a=1', + ); + + // st.equal( + // stringify( + // { a: [, { b: [, , { c: '1' }] }] }, + // { encodeValuesOnly: true, arrayFormat: 'indices' }, + // ), + // 'a[1][b][2][c]=1', + // ); + // st.equal( + // stringify( + // { a: [, { b: [, , { c: '1' }] }] }, + // { encodeValuesOnly: true, arrayFormat: 'brackets' }, + // ), + // 'a[][b][][c]=1', + // ); + // st.equal( + // stringify( + // { a: [, { b: [, , { c: '1' }] }] }, + // { encodeValuesOnly: true, arrayFormat: 'repeat' }, + // ), + // 'a[b][c]=1', + // ); + expect( + stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), + ).toBe('a[1][b][2][c]=1'); + expect( + stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + ).toBe('a[][b][][c]=1'); + expect( + stringify({ a: [, { b: [, , { c: '1' }] }] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), + ).toBe('a[b][c]=1'); + + // st.equal( + // stringify( + // { a: [, [, , [, , , { c: '1' }]]] }, + // { encodeValuesOnly: true, arrayFormat: 'indices' }, + // ), + // 'a[1][2][3][c]=1', + // ); + // st.equal( + // stringify( + // { a: [, [, , [, , , { c: '1' }]]] }, + // { encodeValuesOnly: true, arrayFormat: 'brackets' }, + // ), + // 'a[][][][c]=1', + // ); + // st.equal( + // stringify( + // { a: [, [, , [, , , { c: '1' }]]] }, + // { encodeValuesOnly: true, arrayFormat: 'repeat' }, + // ), + // 'a[c]=1', + // ); + expect( + stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), + ).toBe('a[1][2][3][c]=1'); + expect( + stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + ).toBe('a[][][][c]=1'); + expect( + stringify({ a: [, [, , [, , , { c: '1' }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), + ).toBe('a[c]=1'); + + // st.equal( + // stringify( + // { a: [, [, , [, , , { c: [, '1'] }]]] }, + // { encodeValuesOnly: true, arrayFormat: 'indices' }, + // ), + // 'a[1][2][3][c][1]=1', + // ); + // st.equal( + // stringify( + // { a: [, [, , [, , , { c: [, '1'] }]]] }, + // { encodeValuesOnly: true, arrayFormat: 'brackets' }, + // ), + // 'a[][][][c][]=1', + // ); + // st.equal( + // stringify( + // { a: [, [, , [, , , { c: [, '1'] }]]] }, + // { encodeValuesOnly: true, arrayFormat: 'repeat' }, + // ), + // 'a[c]=1', + // ); + expect( + stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'indices' }), + ).toBe('a[1][2][3][c][1]=1'); + expect( + stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'brackets' }), + ).toBe('a[][][][c][]=1'); + expect( + stringify({ a: [, [, , [, , , { c: [, '1'] }]]] }, { encodeValuesOnly: true, arrayFormat: 'repeat' }), + ).toBe('a[c]=1'); + }); + + test('encodes a very long string', function () { + var chars = []; + var expected = []; + for (var i = 0; i < 5e3; i++) { + chars.push(' ' + i); + + expected.push('%20' + i); + } + + var obj = { + foo: chars.join(''), + }; + + // st.equal( + // stringify(obj, { arrayFormat: 'bracket', charset: 'utf-8' }), + // 'foo=' + expected.join(''), + // ); + // @ts-expect-error + expect(stringify(obj, { arrayFormat: 'bracket', charset: 'utf-8' })).toBe('foo=' + expected.join('')); + }); +}); + +describe('stringifies empty keys', function () { + empty_test_cases.forEach(function (testCase) { + test('stringifies an object with empty string key with ' + testCase.input, function () { + // st.deepEqual( + // stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'indices' }), + // testCase.stringifyOutput.indices, + // 'test case: ' + testCase.input + ', indices', + // ); + // st.deepEqual( + // stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'brackets' }), + // testCase.stringifyOutput.brackets, + // 'test case: ' + testCase.input + ', brackets', + // ); + // st.deepEqual( + // stringify(testCase.withEmptyKeys, { encode: false, arrayFormat: 'repeat' }), + // testCase.stringifyOutput.repeat, + // 'test case: ' + testCase.input + ', repeat', + // ); + expect(stringify(testCase.with_empty_keys, { encode: false, arrayFormat: 'indices' })).toBe( + testCase.stringify_output.indices, + ); + expect(stringify(testCase.with_empty_keys, { encode: false, arrayFormat: 'brackets' })).toBe( + testCase.stringify_output.brackets, + ); + expect(stringify(testCase.with_empty_keys, { encode: false, arrayFormat: 'repeat' })).toBe( + testCase.stringify_output.repeat, + ); + }); + }); + + test('edge case with object/arrays', function () { + // st.deepEqual(stringify({ '': { '': [2, 3] } }, { encode: false }), '[][0]=2&[][1]=3'); + // st.deepEqual( + // stringify({ '': { '': [2, 3], a: 2 } }, { encode: false }), + // '[][0]=2&[][1]=3&[a]=2', + // ); + // st.deepEqual( + // stringify({ '': { '': [2, 3] } }, { encode: false, arrayFormat: 'indices' }), + // '[][0]=2&[][1]=3', + // ); + // st.deepEqual( + // stringify({ '': { '': [2, 3], a: 2 } }, { encode: false, arrayFormat: 'indices' }), + // '[][0]=2&[][1]=3&[a]=2', + // ); + expect(stringify({ '': { '': [2, 3] } }, { encode: false })).toBe('[][0]=2&[][1]=3'); + expect(stringify({ '': { '': [2, 3], a: 2 } }, { encode: false })).toBe('[][0]=2&[][1]=3&[a]=2'); + expect(stringify({ '': { '': [2, 3] } }, { encode: false, arrayFormat: 'indices' })).toBe( + '[][0]=2&[][1]=3', + ); + expect(stringify({ '': { '': [2, 3], a: 2 } }, { encode: false, arrayFormat: 'indices' })).toBe( + '[][0]=2&[][1]=3&[a]=2', + ); + }); +}); diff --git a/tests/qs/utils.test.ts b/tests/qs/utils.test.ts new file mode 100644 index 00000000..07e8e9fc --- /dev/null +++ b/tests/qs/utils.test.ts @@ -0,0 +1,169 @@ +import { combine, merge, is_buffer, assign_single_source } from 'brand.dev/internal/qs/utils'; + +describe('merge()', function () { + // t.deepEqual(merge(null, true), [null, true], 'merges true into null'); + expect(merge(null, true)).toEqual([null, true]); + + // t.deepEqual(merge(null, [42]), [null, 42], 'merges null into an array'); + expect(merge(null, [42])).toEqual([null, 42]); + + // t.deepEqual( + // merge({ a: 'b' }, { a: 'c' }), + // { a: ['b', 'c'] }, + // 'merges two objects with the same key', + // ); + expect(merge({ a: 'b' }, { a: 'c' })).toEqual({ a: ['b', 'c'] }); + + var oneMerged = merge({ foo: 'bar' }, { foo: { first: '123' } }); + // t.deepEqual( + // oneMerged, + // { foo: ['bar', { first: '123' }] }, + // 'merges a standalone and an object into an array', + // ); + expect(oneMerged).toEqual({ foo: ['bar', { first: '123' }] }); + + var twoMerged = merge({ foo: ['bar', { first: '123' }] }, { foo: { second: '456' } }); + // t.deepEqual( + // twoMerged, + // { foo: { 0: 'bar', 1: { first: '123' }, second: '456' } }, + // 'merges a standalone and two objects into an array', + // ); + expect(twoMerged).toEqual({ foo: { 0: 'bar', 1: { first: '123' }, second: '456' } }); + + var sandwiched = merge({ foo: ['bar', { first: '123', second: '456' }] }, { foo: 'baz' }); + // t.deepEqual( + // sandwiched, + // { foo: ['bar', { first: '123', second: '456' }, 'baz'] }, + // 'merges an object sandwiched by two standalones into an array', + // ); + expect(sandwiched).toEqual({ foo: ['bar', { first: '123', second: '456' }, 'baz'] }); + + var nestedArrays = merge({ foo: ['baz'] }, { foo: ['bar', 'xyzzy'] }); + // t.deepEqual(nestedArrays, { foo: ['baz', 'bar', 'xyzzy'] }); + expect(nestedArrays).toEqual({ foo: ['baz', 'bar', 'xyzzy'] }); + + var noOptionsNonObjectSource = merge({ foo: 'baz' }, 'bar'); + // t.deepEqual(noOptionsNonObjectSource, { foo: 'baz', bar: true }); + expect(noOptionsNonObjectSource).toEqual({ foo: 'baz', bar: true }); + + (typeof Object.defineProperty !== 'function' ? test.skip : test)( + 'avoids invoking array setters unnecessarily', + function () { + var setCount = 0; + var getCount = 0; + var observed: any[] = []; + Object.defineProperty(observed, 0, { + get: function () { + getCount += 1; + return { bar: 'baz' }; + }, + set: function () { + setCount += 1; + }, + }); + merge(observed, [null]); + // st.equal(setCount, 0); + // st.equal(getCount, 1); + expect(setCount).toEqual(0); + expect(getCount).toEqual(1); + observed[0] = observed[0]; + // st.equal(setCount, 1); + // st.equal(getCount, 2); + expect(setCount).toEqual(1); + expect(getCount).toEqual(2); + }, + ); +}); + +test('assign()', function () { + var target = { a: 1, b: 2 }; + var source = { b: 3, c: 4 }; + var result = assign_single_source(target, source); + + expect(result).toEqual(target); + expect(target).toEqual({ a: 1, b: 3, c: 4 }); + expect(source).toEqual({ b: 3, c: 4 }); +}); + +describe('combine()', function () { + test('both arrays', function () { + var a = [1]; + var b = [2]; + var combined = combine(a, b); + + // st.deepEqual(a, [1], 'a is not mutated'); + // st.deepEqual(b, [2], 'b is not mutated'); + // st.notEqual(a, combined, 'a !== combined'); + // st.notEqual(b, combined, 'b !== combined'); + // st.deepEqual(combined, [1, 2], 'combined is a + b'); + expect(a).toEqual([1]); + expect(b).toEqual([2]); + expect(combined).toEqual([1, 2]); + expect(a).not.toEqual(combined); + expect(b).not.toEqual(combined); + }); + + test('one array, one non-array', function () { + var aN = 1; + var a = [aN]; + var bN = 2; + var b = [bN]; + + var combinedAnB = combine(aN, b); + // st.deepEqual(b, [bN], 'b is not mutated'); + // st.notEqual(aN, combinedAnB, 'aN + b !== aN'); + // st.notEqual(a, combinedAnB, 'aN + b !== a'); + // st.notEqual(bN, combinedAnB, 'aN + b !== bN'); + // st.notEqual(b, combinedAnB, 'aN + b !== b'); + // st.deepEqual([1, 2], combinedAnB, 'first argument is array-wrapped when not an array'); + expect(b).toEqual([bN]); + expect(combinedAnB).not.toEqual(aN); + expect(combinedAnB).not.toEqual(a); + expect(combinedAnB).not.toEqual(bN); + expect(combinedAnB).not.toEqual(b); + expect(combinedAnB).toEqual([1, 2]); + + var combinedABn = combine(a, bN); + // st.deepEqual(a, [aN], 'a is not mutated'); + // st.notEqual(aN, combinedABn, 'a + bN !== aN'); + // st.notEqual(a, combinedABn, 'a + bN !== a'); + // st.notEqual(bN, combinedABn, 'a + bN !== bN'); + // st.notEqual(b, combinedABn, 'a + bN !== b'); + // st.deepEqual([1, 2], combinedABn, 'second argument is array-wrapped when not an array'); + expect(a).toEqual([aN]); + expect(combinedABn).not.toEqual(aN); + expect(combinedABn).not.toEqual(a); + expect(combinedABn).not.toEqual(bN); + expect(combinedABn).not.toEqual(b); + expect(combinedABn).toEqual([1, 2]); + }); + + test('neither is an array', function () { + var combined = combine(1, 2); + // st.notEqual(1, combined, '1 + 2 !== 1'); + // st.notEqual(2, combined, '1 + 2 !== 2'); + // st.deepEqual([1, 2], combined, 'both arguments are array-wrapped when not an array'); + expect(combined).not.toEqual(1); + expect(combined).not.toEqual(2); + expect(combined).toEqual([1, 2]); + }); +}); + +test('is_buffer()', function () { + for (const x of [null, undefined, true, false, '', 'abc', 42, 0, NaN, {}, [], function () {}, /a/g]) { + // t.equal(is_buffer(x), false, inspect(x) + ' is not a buffer'); + expect(is_buffer(x)).toEqual(false); + } + + var fakeBuffer = { constructor: Buffer }; + // t.equal(is_buffer(fakeBuffer), false, 'fake buffer is not a buffer'); + expect(is_buffer(fakeBuffer)).toEqual(false); + + var saferBuffer = Buffer.from('abc'); + // t.equal(is_buffer(saferBuffer), true, 'SaferBuffer instance is a buffer'); + expect(is_buffer(saferBuffer)).toEqual(true); + + var buffer = Buffer.from('abc'); + // t.equal(is_buffer(buffer), true, 'real Buffer instance is a buffer'); + expect(is_buffer(buffer)).toEqual(true); +}); diff --git a/tests/stringifyQuery.test.ts b/tests/stringifyQuery.test.ts index 77f661a1..704398e3 100644 --- a/tests/stringifyQuery.test.ts +++ b/tests/stringifyQuery.test.ts @@ -18,10 +18,4 @@ describe(stringifyQuery, () => { expect(stringifyQuery(input)).toEqual(expected); }); } - - for (const value of [[], {}, new Date()]) { - it(`${JSON.stringify(value)} -> `, () => { - expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); - }); - } }); From 808759cee7444f52175b1d2a2558468454a348c6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 23:08:33 +0000 Subject: [PATCH 053/100] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 42 +++++++++++----- src/resources/brand.ts | 50 +++++++++++++++++++- tests/api-resources/brand.test.ts | 11 ++++- 4 files changed, 92 insertions(+), 15 deletions(-) diff --git a/.stats.yml b/.stats.yml index 71256d4c..399384d4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-f4118654961d5928e40ebe0771eb12f9aa1ca68cf9268bf3400eb1ab8b4dae1a.yml -openapi_spec_hash: ff26efd9c23ca8d4ed2c84f1716280c4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-e299f3a9f343788f804eb0f7d71c609bf811bea363547ead01482e54612c3b37.yml +openapi_spec_hash: 4d17210ddd28eca4c39f89e5b864d066 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 24d61089..2a042656 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -58,11 +58,17 @@ const EMBEDDED_METHODS: MethodEntry[] = [ description: 'Retrieve logos, backdrops, colors, industry, description, and more from any domain', stainlessPath: '(resource) brand > (method) retrieve', qualified: 'client.brand.retrieve', - params: ['domain: string;', 'force_language?: string;', 'maxSpeed?: boolean;', 'timeoutMS?: number;'], + params: [ + 'domain: string;', + 'force_language?: string;', + 'maxAgeMs?: number;', + 'maxSpeed?: boolean;', + 'timeoutMS?: number;', + ], response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve\n\n`client.brand.retrieve(domain: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve`\n\nRetrieve logos, backdrops, colors, industry, description, and more from any domain\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve brand data for (e.g., 'example.com', 'google.com'). Cannot be used with name or ticker parameters.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data. Works with all three lookup methods.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst brand = await client.brand.retrieve({ domain: 'domain' });\n\nconsole.log(brand);\n```", + "## retrieve\n\n`client.brand.retrieve(domain: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve`\n\nRetrieve logos, backdrops, colors, industry, description, and more from any domain\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve brand data for (e.g., 'example.com', 'google.com'). Cannot be used with name or ticker parameters.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data. Works with all three lookup methods.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst brand = await client.brand.retrieve({ domain: 'domain' });\n\nconsole.log(brand);\n```", perLanguage: { typescript: { method: 'client.brand.retrieve', @@ -101,6 +107,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ params: [ 'ticker: string;', 'force_language?: string;', + 'maxAgeMs?: number;', 'maxSpeed?: boolean;', 'ticker_exchange?: string;', 'timeoutMS?: number;', @@ -108,7 +115,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_ticker\n\n`client.brand.retrieveByTicker(ticker: string, force_language?: string, maxSpeed?: boolean, ticker_exchange?: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-ticker`\n\nRetrieve brand information using a stock ticker symbol.\n\n### Parameters\n\n- `ticker: string`\n Stock ticker symbol to retrieve brand data for (e.g., 'AAPL', 'GOOGL', 'BRK.A'). Must be 1-15 characters, letters/numbers/dots only.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `ticker_exchange?: string`\n Optional stock exchange for the ticker. Defaults to NASDAQ if not specified.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response);\n```", + "## retrieve_by_ticker\n\n`client.brand.retrieveByTicker(ticker: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, ticker_exchange?: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-ticker`\n\nRetrieve brand information using a stock ticker symbol.\n\n### Parameters\n\n- `ticker: string`\n Stock ticker symbol to retrieve brand data for (e.g., 'AAPL', 'GOOGL', 'BRK.A'). Must be 1-15 characters, letters/numbers/dots only.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `ticker_exchange?: string`\n Optional stock exchange for the ticker. Defaults to NASDAQ if not specified.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveByTicker', @@ -145,11 +152,17 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'Retrieve brand information using an ISIN (International Securities Identification Number). ', stainlessPath: '(resource) brand > (method) retrieve_by_isin', qualified: 'client.brand.retrieveByIsin', - params: ['isin: string;', 'force_language?: string;', 'maxSpeed?: boolean;', 'timeoutMS?: number;'], + params: [ + 'isin: string;', + 'force_language?: string;', + 'maxAgeMs?: number;', + 'maxSpeed?: boolean;', + 'timeoutMS?: number;', + ], response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_isin\n\n`client.brand.retrieveByIsin(isin: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-isin`\n\nRetrieve brand information using an ISIN (International Securities Identification Number). \n\n### Parameters\n\n- `isin: string`\n ISIN (International Securities Identification Number) to retrieve brand data for (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters followed by 9 alphanumeric characters and ending with a digit.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response);\n```", + "## retrieve_by_isin\n\n`client.brand.retrieveByIsin(isin: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-isin`\n\nRetrieve brand information using an ISIN (International Securities Identification Number). \n\n### Parameters\n\n- `isin: string`\n ISIN (International Securities Identification Number) to retrieve brand data for (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters followed by 9 alphanumeric characters and ending with a digit.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveByIsin', @@ -189,13 +202,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'name: string;', 'country_gl?: string;', 'force_language?: string;', + 'maxAgeMs?: number;', 'maxSpeed?: boolean;', 'timeoutMS?: number;', ], response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_name\n\n`client.brand.retrieveByName(name: string, country_gl?: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-name`\n\nRetrieve brand information using a company name.\n\n### Parameters\n\n- `name: string`\n Company name to retrieve brand data for (e.g., 'Apple Inc', 'Microsoft Corporation'). Must be 3-30 characters.\n\n- `country_gl?: string`\n Optional country code hint (GL parameter) to specify the country for the company name.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response);\n```", + "## retrieve_by_name\n\n`client.brand.retrieveByName(name: string, country_gl?: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-name`\n\nRetrieve brand information using a company name.\n\n### Parameters\n\n- `name: string`\n Company name to retrieve brand data for (e.g., 'Apple Inc', 'Microsoft Corporation'). Must be 3-30 characters.\n\n- `country_gl?: string`\n Optional country code hint (GL parameter) to specify the country for the company name.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveByName', @@ -232,11 +246,17 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'Retrieve brand information using an email address while detecting disposable and free email addresses. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.', stainlessPath: '(resource) brand > (method) retrieve_by_email', qualified: 'client.brand.retrieveByEmail', - params: ['email: string;', 'force_language?: string;', 'maxSpeed?: boolean;', 'timeoutMS?: number;'], + params: [ + 'email: string;', + 'force_language?: string;', + 'maxAgeMs?: number;', + 'maxSpeed?: boolean;', + 'timeoutMS?: number;', + ], response: "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_by_email\n\n`client.brand.retrieveByEmail(email: string, force_language?: string, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-email`\n\nRetrieve brand information using an email address while detecting disposable and free email addresses. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.\n\n### Parameters\n\n- `email: string`\n Email address to retrieve brand data for (e.g., 'contact@example.com'). The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", + "## retrieve_by_email\n\n`client.brand.retrieveByEmail(email: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-email`\n\nRetrieve brand information using an email address while detecting disposable and free email addresses. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.\n\n### Parameters\n\n- `email: string`\n Email address to retrieve brand data for (e.g., 'contact@example.com'). The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveByEmail', @@ -449,11 +469,11 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'Returns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. Optimized for faster responses and reduced data transfer.', stainlessPath: '(resource) brand > (method) retrieve_simplified', qualified: 'client.brand.retrieveSimplified', - params: ['domain: string;', 'timeoutMS?: number;'], + params: ['domain: string;', 'maxAgeMs?: number;', 'timeoutMS?: number;'], response: "{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; status?: string; }", markdown: - "## retrieve_simplified\n\n`client.brand.retrieveSimplified(domain: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-simplified`\n\nReturns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. Optimized for faster responses and reduced data transfer.\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve simplified brand data for\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- `{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveSimplified({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## retrieve_simplified\n\n`client.brand.retrieveSimplified(domain: string, maxAgeMs?: number, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-simplified`\n\nReturns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. Optimized for faster responses and reduced data transfer.\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve simplified brand data for\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\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- `{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveSimplified({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveSimplified', @@ -667,7 +687,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }", markdown: - "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 6000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeImages', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 77672793..8e939665 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -5425,6 +5425,14 @@ export interface BrandRetrieveParams { | 'yoruba' | 'zulu'; + /** + * Maximum age in milliseconds for cached brand data before the API performs a hard + * refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) + * are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 + * year. + */ + maxAgeMs?: number; + /** * Optional parameter to optimize the API call for maximum speed. When set to true, * the API will skip time-consuming operations for faster response at the cost of @@ -6201,6 +6209,14 @@ export interface BrandRetrieveByEmailParams { | 'yoruba' | 'zulu'; + /** + * Maximum age in milliseconds for cached brand data before the API performs a hard + * refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) + * are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 + * year. + */ + maxAgeMs?: number; + /** * Optional parameter to optimize the API call for maximum speed. When set to true, * the API will skip time-consuming operations for faster response at the cost of @@ -6349,6 +6365,14 @@ export interface BrandRetrieveByIsinParams { | 'yoruba' | 'zulu'; + /** + * Maximum age in milliseconds for cached brand data before the API performs a hard + * refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) + * are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 + * year. + */ + maxAgeMs?: number; + /** * Optional parameter to optimize the API call for maximum speed. When set to true, * the API will skip time-consuming operations for faster response at the cost of @@ -6741,6 +6765,14 @@ export interface BrandRetrieveByNameParams { | 'yoruba' | 'zulu'; + /** + * Maximum age in milliseconds for cached brand data before the API performs a hard + * refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) + * are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 + * year. + */ + maxAgeMs?: number; + /** * Optional parameter to optimize the API call for maximum speed. When set to true, * the API will skip time-consuming operations for faster response at the cost of @@ -6888,6 +6920,14 @@ export interface BrandRetrieveByTickerParams { | 'yoruba' | 'zulu'; + /** + * Maximum age in milliseconds for cached brand data before the API performs a hard + * refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) + * are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 + * year. + */ + maxAgeMs?: number; + /** * Optional parameter to optimize the API call for maximum speed. When set to true, * the API will skip time-consuming operations for faster response at the cost of @@ -6986,6 +7026,14 @@ export interface BrandRetrieveSimplifiedParams { */ domain: string; + /** + * Maximum age in milliseconds for cached brand data before the API performs a hard + * refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) + * are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 + * year. + */ + maxAgeMs?: number; + /** * 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 @@ -7057,7 +7105,7 @@ export namespace BrandWebScrapeImagesParams { hostedUrl?: boolean; /** - * Per-image enrichment timeout in milliseconds. Default: 6000. Maximum: 60000. + * Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000. */ maxTimePerMs?: number; diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 0cb92a68..20030792 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -25,6 +25,7 @@ describe('resource brand', () => { const response = await client.brand.retrieve({ domain: 'domain', force_language: 'afrikaans', + maxAgeMs: 86400000, maxSpeed: true, timeoutMS: 1000, }); @@ -202,6 +203,7 @@ describe('resource brand', () => { const response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com', force_language: 'afrikaans', + maxAgeMs: 86400000, maxSpeed: true, timeoutMS: 1000, }); @@ -224,6 +226,7 @@ describe('resource brand', () => { const response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993', force_language: 'afrikaans', + maxAgeMs: 86400000, maxSpeed: true, timeoutMS: 1000, }); @@ -247,6 +250,7 @@ describe('resource brand', () => { name: 'xxx', country_gl: 'ad', force_language: 'afrikaans', + maxAgeMs: 86400000, maxSpeed: true, timeoutMS: 1000, }); @@ -269,6 +273,7 @@ describe('resource brand', () => { const response = await client.brand.retrieveByTicker({ ticker: 'ticker', force_language: 'afrikaans', + maxAgeMs: 86400000, maxSpeed: true, ticker_exchange: 'AMEX', timeoutMS: 1000, @@ -289,7 +294,11 @@ describe('resource brand', () => { // Mock server tests are disabled test.skip('retrieveSimplified: required and optional params', async () => { - const response = await client.brand.retrieveSimplified({ domain: 'domain', timeoutMS: 1000 }); + const response = await client.brand.retrieveSimplified({ + domain: 'domain', + maxAgeMs: 86400000, + timeoutMS: 1000, + }); }); // Mock server tests are disabled From 7beb2df9748e4d4ba908fedf97d5ee8256e1c89c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 02:27:09 +0000 Subject: [PATCH 054/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 399384d4..4178b182 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-e299f3a9f343788f804eb0f7d71c609bf811bea363547ead01482e54612c3b37.yml -openapi_spec_hash: 4d17210ddd28eca4c39f89e5b864d066 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-084a13c80f616458adab7dd3da1df26c7b18002770bf0c866a61fbde2ab5a1e2.yml +openapi_spec_hash: e7b22a44a4023bc6a89508368636b3a6 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 3a511e140051649ac3ce35051d91e2adb4dd2765 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 03:01:42 +0000 Subject: [PATCH 055/100] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 22 ++++++---- src/resources/brand.ts | 43 +++++++++++++++++--- tests/api-resources/brand.test.ts | 4 ++ 4 files changed, 58 insertions(+), 15 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4178b182..3647616d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-084a13c80f616458adab7dd3da1df26c7b18002770bf0c866a61fbde2ab5a1e2.yml -openapi_spec_hash: e7b22a44a4023bc6a89508368636b3a6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-f930a89f5fccd44dd6548fce8ae69ab2d966dd10a3e3dfa128a8894089a34d1a.yml +openapi_spec_hash: d21ebf5fac677f08d74a9153fb57f9af config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 2a042656..ef1ffeef 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -555,7 +555,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ is_product_page?: boolean; 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; }; }", markdown: - "## ai_product\n\n`client.brand.aiProduct(url: string, maxAgeMs?: number, timeoutMS?: number): { is_product_page?: boolean; 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- `timeoutMS?: number`\n Optional timeout in milliseconds for the request. Maximum allowed value is 300000ms (5 minutes).\n\n### Returns\n\n- `{ is_product_page?: boolean; 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 - `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## ai_product\n\n`client.brand.aiProduct(url: string, maxAgeMs?: number, timeoutMS?: number): { is_product_page?: boolean; 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- `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; 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 - `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.aiProduct', @@ -591,10 +591,16 @@ const EMBEDDED_METHODS: MethodEntry[] = [ description: 'Scrapes the given URL and returns the raw HTML content of the page.', stainlessPath: '(resource) brand > (method) web_scrape_html', qualified: 'client.brand.webScrapeHTML', - params: ['url: string;', 'includeFrames?: boolean;', 'maxAgeMs?: number;', 'parsePDF?: boolean;'], + params: [ + 'url: string;', + 'includeFrames?: boolean;', + 'maxAgeMs?: number;', + 'parsePDF?: boolean;', + 'timeoutMS?: number;', + ], response: '{ html: string; success: true; url: string; }', markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, includeFrames?: boolean, maxAgeMs?: number, parsePDF?: boolean): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and returned wrapped in . When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, includeFrames?: boolean, maxAgeMs?: number, parsePDF?: boolean, timeoutMS?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and returned wrapped in . When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\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- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', @@ -638,11 +644,12 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'maxAgeMs?: number;', 'parsePDF?: boolean;', 'shortenBase64Images?: boolean;', + 'timeoutMS?: number;', 'useMainContentOnly?: boolean;', ], response: '{ markdown: string; success: true; url: string; }', markdown: - "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, parsePDF?: boolean, shortenBase64Images?: boolean, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and converted to Markdown. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\n\n- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, parsePDF?: boolean, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and converted to Markdown. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeMd', @@ -683,11 +690,12 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'url: string;', 'enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; };', 'maxAgeMs?: number;', + 'timeoutMS?: number;', ], response: "{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }", markdown: - "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number, timeoutMS?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\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- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeImages', @@ -723,11 +731,11 @@ const EMBEDDED_METHODS: MethodEntry[] = [ description: "Crawl an entire website's sitemap and return all discovered page URLs.", stainlessPath: '(resource) brand > (method) web_scrape_sitemap', qualified: 'client.brand.webScrapeSitemap', - params: ['domain: string;', 'maxLinks?: number;', 'urlRegex?: string;'], + params: ['domain: string;', 'maxLinks?: number;', 'timeoutMS?: number;', 'urlRegex?: string;'], response: '{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }', markdown: - "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number, urlRegex?: string): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\n\n- `urlRegex?: string`\n Optional RE2-compatible regex pattern. Only URLs matching this pattern are returned and counted against maxLinks.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number, timeoutMS?: number, urlRegex?: string): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\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 Optional RE2-compatible regex pattern. Only URLs matching this pattern are returned and counted against maxLinks.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeSitemap', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 8e939665..9a2130b4 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -5462,8 +5462,9 @@ export interface BrandAIProductParams { maxAgeMs?: number; /** - * Optional timeout in milliseconds for the request. Maximum allowed value is - * 300000ms (5 minutes). + * 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). */ timeoutMS?: number; } @@ -5490,8 +5491,9 @@ export declare namespace BrandAIProductsParams { maxProducts?: number; /** - * Optional timeout in milliseconds for the request. Maximum allowed value is - * 300000ms (5 minutes). + * 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). */ timeoutMS?: number; } @@ -5516,8 +5518,9 @@ export declare namespace BrandAIProductsParams { maxProducts?: number; /** - * Optional timeout in milliseconds for the request. Maximum allowed value is - * 300000ms (5 minutes). + * 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). */ timeoutMS?: number; } @@ -7066,6 +7069,13 @@ export interface BrandWebScrapeHTMLParams { * and a 400 WEBSITE_ACCESS_ERROR is returned. */ parsePDF?: boolean; + + /** + * 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). + */ + timeoutMS?: number; } export interface BrandWebScrapeImagesParams { @@ -7085,6 +7095,13 @@ export interface BrandWebScrapeImagesParams { * day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days). */ maxAgeMs?: number; + + /** + * 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). + */ + timeoutMS?: number; } export namespace BrandWebScrapeImagesParams { @@ -7157,6 +7174,13 @@ export interface BrandWebScrapeMdParams { */ shortenBase64Images?: boolean; + /** + * 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). + */ + timeoutMS?: number; + /** * Extract only the main content of the page, excluding headers, footers, sidebars, * and navigation @@ -7176,6 +7200,13 @@ export interface BrandWebScrapeSitemapParams { */ maxLinks?: number; + /** + * 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). + */ + timeoutMS?: number; + /** * Optional RE2-compatible regex pattern. Only URLs matching this pattern are * returned and counted against maxLinks. diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 20030792..e330635c 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -320,6 +320,7 @@ describe('resource brand', () => { includeFrames: true, maxAgeMs: 0, parsePDF: true, + timeoutMS: 1000, }); }); @@ -346,6 +347,7 @@ describe('resource brand', () => { resolution: true, }, maxAgeMs: 0, + timeoutMS: 1000, }); }); @@ -371,6 +373,7 @@ describe('resource brand', () => { maxAgeMs: 0, parsePDF: true, shortenBase64Images: true, + timeoutMS: 1000, useMainContentOnly: true, }); }); @@ -392,6 +395,7 @@ describe('resource brand', () => { const response = await client.brand.webScrapeSitemap({ domain: 'domain', maxLinks: 1, + timeoutMS: 1000, urlRegex: '^https?://[^/]+/blog/', }); }); From a4e5d6c3560d675b3a1417ca2c62a236d89079f8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 04:41:28 +0000 Subject: [PATCH 056/100] docs: update logging docs --- packages/mcp-server/src/local-docs-search.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index ef1ffeef..2e1964f6 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -769,7 +769,7 @@ const EMBEDDED_READMES: { language: string; content: string }[] = [ { language: 'java', content: - '# Brand Dev Java API Library\n\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.0.1)\n[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1)\n\n\nThe Brand Dev Java SDK provides convenient access to the [Brand Dev REST API](https://docs.context.dev/) from applications written in Java.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1).\n\n\n\n## Installation\n\n\n\n### Gradle\n\n~~~kotlin\nimplementation("com.branddev.api:brand-dev-java:0.0.1")\n~~~\n\n### Maven\n\n~~~xml\n\n com.branddev.api\n brand-dev-java\n 0.0.1\n\n~~~\n\n\n\n## Requirements\n\nThis library requires Java 8 or later.\n\n## Usage\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nBrandRetrieveResponse brand = client.brand().retrieve(params);\n```\n\n## Client configuration\n\nConfigure the client using system properties or environment variables:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n```\n\nOr manually:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .apiKey("My API Key")\n .build();\n```\n\nOr using a combination of the two approaches:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n // Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n // Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\n .fromEnv()\n .apiKey("My API Key")\n .build();\n```\n\nSee this table for the available options:\n\n| Setter | System property | Environment variable | Required | Default value |\n| --------- | ------------------ | -------------------- | -------- | ---------------------------- |\n| `apiKey` | `branddev.apiKey` | `BRAND_DEV_API_KEY` | true | - |\n| `baseUrl` | `branddev.baseUrl` | `BRAND_DEV_BASE_URL` | true | `"https://api.brand.dev/v1"` |\n\nSystem properties take precedence over environment variables.\n\n> [!TIP]\n> Don\'t create more than one client in the same application. Each client has a connection pool and\n> thread pools, which are more efficient to share between requests.\n\n### Modifying configuration\n\nTo temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\n\nBrandDevClient clientWithOptions = client.withOptions(optionsBuilder -> {\n optionsBuilder.baseUrl("https://example.com");\n optionsBuilder.maxRetries(42);\n});\n```\n\nThe `withOptions()` method does not affect the original client or service.\n\n## Requests and responses\n\nTo send a request to the Brand Dev API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.\n\nFor example, `client.brand().retrieve(...)` should be called with an instance of `BrandRetrieveParams`, and it will return an instance of `BrandRetrieveResponse`.\n\n## Immutability\n\nEach class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.\n\nEach class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.\n\nBecause each class is immutable, builder modification will _never_ affect already built class instances.\n\n## Asynchronous execution\n\nThe default client is synchronous. To switch to asynchronous execution, call the `async()` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.async().brand().retrieve(params);\n```\n\nOr create an asynchronous client from the beginning:\n\n```java\nimport com.branddev.api.client.BrandDevClientAsync;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClientAsync;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClientAsync client = BrandDevOkHttpClientAsync.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.brand().retrieve(params);\n```\n\nThe asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.\n\n\n\n\n\n\n\n## Raw responses\n\nThe SDK defines methods that deserialize responses into instances of Java classes. However, these methods don\'t provide access to the response headers, status code, or the raw response body.\n\nTo access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:\n\n```java\nimport com.branddev.api.core.http.Headers;\nimport com.branddev.api.core.http.HttpResponseFor;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nHttpResponseFor brand = client.brand().withRawResponse().retrieve(params);\n\nint statusCode = brand.statusCode();\nHeaders headers = brand.headers();\n```\n\nYou can still deserialize the response into an instance of a Java class if needed:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse parsedBrand = brand.parse();\n```\n\n## Error handling\n\nThe SDK throws custom unchecked exception types:\n\n- [`BrandDevServiceException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:\n\n | Status | Exception |\n | ------ | -------------------------------------------------- |\n | 400 | [`BadRequestException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BadRequestException.kt) |\n | 401 | [`UnauthorizedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnauthorizedException.kt) |\n | 403 | [`PermissionDeniedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/PermissionDeniedException.kt) |\n | 404 | [`NotFoundException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/NotFoundException.kt) |\n | 422 | [`UnprocessableEntityException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnprocessableEntityException.kt) |\n | 429 | [`RateLimitException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/RateLimitException.kt) |\n | 5xx | [`InternalServerException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/InternalServerException.kt) |\n | others | [`UnexpectedStatusCodeException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnexpectedStatusCodeException.kt) |\n\n- [`BrandDevIoException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevIoException.kt): I/O networking errors.\n\n- [`BrandDevRetryableException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevRetryableException.kt): Generic error indicating a failure that could be retried by the client.\n\n- [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that\'s supposed to be required, but the API unexpectedly omitted it from the response.\n\n- [`BrandDevException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.\n\n\n\n## Logging\n\nThe SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor).\n\nEnable logging by setting the `BRAND_DEV_LOG` environment variable to `info`:\n\n```sh\nexport BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging:\n\n```sh\nexport BRAND_DEV_LOG=debug\n```\n\n## ProGuard and R8\n\nAlthough the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `brand-dev-java-core` is published with a [configuration file](brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).\n\nProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.\n\n\n\n\n\n## Jackson\n\nThe SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.\n\nThe SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).\n\nIf the SDK threw an exception, but you\'re _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt).\n\n> [!CAUTION]\n> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.\n\nAlso note that there are bugs in older Jackson versions that can affect the SDK. We don\'t work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead.\n\n## Network options\n\n### Retries\n\nThe SDK automatically retries 2 times by default, with a short exponential backoff between requests.\n\nOnly the following error types are retried:\n- Connection errors (for example, due to a network connectivity problem)\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- 5xx Internal\n\nThe API may also explicitly instruct the SDK to retry or not retry a request.\n\nTo set a custom number of retries, configure the client using the `maxRetries` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .maxRetries(4)\n .build();\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default.\n\nTo set a custom timeout, configure the method call using the `timeout` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .timeout(Duration.ofSeconds(30))\n .build();\n```\n\n### Proxies\n\nTo route requests through a proxy, configure the client using the `proxy` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(new Proxy(\n Proxy.Type.HTTP, new InetSocketAddress(\n "https://example.com", 8080\n )\n ))\n .build();\n```\n\nIf the proxy responds with `407 Proxy Authentication Required`, supply credentials by also configuring `proxyAuthenticator`:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.core.http.ProxyAuthenticator;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(...)\n // Or a custom implementation of `ProxyAuthenticator`.\n .proxyAuthenticator(ProxyAuthenticator.basic("username", "password"))\n .build();\n```\n\n### Connection pooling\n\nTo customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.\n .maxIdleConnections(10)\n .keepAliveDuration(Duration.ofMinutes(2))\n .build();\n```\n\nIf both options are unset, OkHttp\'s default connection pool settings are used.\n\n### HTTPS\n\n> [!NOTE]\n> Most applications should not call these methods, and instead use the system defaults. The defaults include\n> special optimizations that can be lost if the implementations are modified.\n\nTo configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.\n .sslSocketFactory(yourSSLSocketFactory)\n .trustManager(yourTrustManager)\n .hostnameVerifier(yourHostnameVerifier)\n .build();\n```\n\n\n\n### Custom HTTP client\n\nThe SDK consists of three artifacts:\n- `brand-dev-java-core`\n - Contains core SDK logic\n - Does not depend on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClient.kt), [`BrandDevClientAsync`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsync.kt), [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt), and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), all of which can work with any HTTP client\n- `brand-dev-java-client-okhttp`\n - Depends on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) and [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), which provide a way to construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), respectively, using OkHttp\n- `brand-dev-java`\n - Depends on and exposes the APIs of both `brand-dev-java-core` and `brand-dev-java-client-okhttp`\n - Does not have its own logic\n\nThis structure allows replacing the SDK\'s default HTTP client without pulling in unnecessary dependencies.\n\n#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)\n\n> [!TIP]\n> Try the available [network options](#network-options) before replacing the default client.\n\nTo use a customized `OkHttpClient`:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Copy `brand-dev-java-client-okhttp`\'s [`OkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/OkHttpClient.kt) class into your code and customize it\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your customized client\n\n### Completely custom HTTP client\n\nTo use a completely custom HTTP client:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Write a class that implements the [`HttpClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/http/HttpClient.kt) interface\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your new client class\n\n## Undocumented API functionality\n\nThe SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.\n\n### Parameters\n\nTo set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .putAdditionalHeader("Secret-Header", "42")\n .putAdditionalQueryParam("secret_query_param", "42")\n .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))\n .build();\n```\n\nThese can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.\n\nTo set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\n\nBrandAiQueryParams params = BrandAiQueryParams.builder()\n .specificPages(BrandAiQueryParams.SpecificPages.builder()\n .putAdditionalProperty("secretProperty", JsonValue.from("42"))\n .build())\n .build();\n```\n\nThese properties can be accessed on the nested built object later using the `_additionalProperties()` method.\n\nTo set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) object to its setter:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\n```\n\nThe most straightforward way to create a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) is using its `from(...)` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.List;\nimport java.util.Map;\n\n// Create primitive JSON values\nJsonValue nullValue = JsonValue.from(null);\nJsonValue booleanValue = JsonValue.from(true);\nJsonValue numberValue = JsonValue.from(42);\nJsonValue stringValue = JsonValue.from("Hello World!");\n\n// Create a JSON array value equivalent to `["Hello", "World"]`\nJsonValue arrayValue = JsonValue.from(List.of(\n "Hello", "World"\n));\n\n// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`\nJsonValue objectValue = JsonValue.from(Map.of(\n "a", 1,\n "b", 2\n));\n\n// Create an arbitrarily nested JSON equivalent to:\n// {\n// "a": [1, 2],\n// "b": [3, 4]\n// }\nJsonValue complexValue = JsonValue.from(Map.of(\n "a", List.of(\n 1, 2\n ),\n "b", List.of(\n 3, 4\n )\n));\n```\n\nNormally a `Builder` class\'s `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.\n\nTo forcibly omit a required parameter or property, pass [`JsonMissing`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt):\n\n```java\nimport com.branddev.api.core.JsonMissing;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain(JsonMissing.of())\n .build();\n```\n\n### Response properties\n\nTo access undocumented response properties, call the `_additionalProperties()` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.Map;\n\nMap additionalProperties = client.brand().retrieve(params)._additionalProperties();\nJsonValue secretPropertyValue = additionalProperties.get("secretProperty");\n\nString result = secretPropertyValue.accept(new JsonValue.Visitor<>() {\n @Override\n public String visitNull() {\n return "It\'s null!";\n }\n\n @Override\n public String visitBoolean(boolean value) {\n return "It\'s a boolean!";\n }\n\n @Override\n public String visitNumber(Number value) {\n return "It\'s a number!";\n }\n\n // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`\n // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden\n});\n```\n\nTo access a property\'s raw JSON value, which may be undocumented, call its `_` prefixed method:\n\n```java\nimport com.branddev.api.core.JsonField;\nimport java.util.Optional;\n\nJsonField field = client.brand().retrieve(params)._field();\n\nif (field.isMissing()) {\n // The property is absent from the JSON response\n} else if (field.isNull()) {\n // The property was set to literal null\n} else {\n // Check if value was provided as a string\n // Other methods include `asNumber()`, `asBoolean()`, etc.\n Optional jsonString = field.asString();\n\n // Try to deserialize into a custom type\n MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class);\n}\n```\n\n### Response validation\n\nIn rare cases, the API may return a response that doesn\'t match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.\n\nBy default, the SDK will not throw an exception in this case. It will throw [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt) only if you directly access the property.\n\nValidating the response is _not_ forwards compatible with new types from the API for existing fields.\n\nIf you would still prefer to check that the response is completely well-typed upfront, then either call `validate()`:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(params).validate();\n```\n\nOr configure the method call to validate the response using the `responseValidation` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().responseValidation(true).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .responseValidation(true)\n .build();\n```\n\n## FAQ\n\n### Why don\'t you use plain `enum` classes?\n\nJava `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.\n\n### Why do you represent fields using `JsonField` instead of just plain `T`?\n\nUsing `JsonField` enables a few features:\n\n- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)\n- Lazily [validating the API response against the expected shape](#response-validation)\n- Representing absent vs explicitly null values\n\n### Why don\'t you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?\n\nIt is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don\'t want to introduce a breaking change every time we add a field to a class.\n\n### Why don\'t you use checked exceptions?\n\nChecked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.\n\nChecked exceptions:\n\n- Are verbose to handle\n- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error\n- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)\n- Don\'t play well with lambdas (also due to the function coloring problem)\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-java-sdk/issues) with questions, bugs, or suggestions.\n', + '# Brand Dev Java API Library\n\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.branddev.api/brand-dev-java)](https://central.sonatype.com/artifact/com.branddev.api/brand-dev-java/0.0.1)\n[![javadoc](https://javadoc.io/badge2/com.branddev.api/brand-dev-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1)\n\n\nThe Brand Dev Java SDK provides convenient access to the [Brand Dev REST API](https://docs.context.dev/) from applications written in Java.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Brand Dev MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=brand.dev-mcp&config=eyJuYW1lIjoiYnJhbmQuZGV2LW1jcCIsInRyYW5zcG9ydCI6Imh0dHAiLCJ1cmwiOiJodHRwczovL2JyYW5kLWRldi5zdGxtY3AuY29tIiwiaGVhZGVycyI6eyJ4LWJyYW5kLWRldi1hcGkta2V5IjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22brand.dev-mcp%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fbrand-dev.stlmcp.com%22%2C%22headers%22%3A%7B%22x-brand-dev-api-key%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n\n\nThe REST API documentation can be found on [docs.context.dev](https://docs.context.dev/). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.branddev.api/brand-dev-java/0.0.1).\n\n\n\n## Installation\n\n\n\n### Gradle\n\n~~~kotlin\nimplementation("com.branddev.api:brand-dev-java:0.0.1")\n~~~\n\n### Maven\n\n~~~xml\n\n com.branddev.api\n brand-dev-java\n 0.0.1\n\n~~~\n\n\n\n## Requirements\n\nThis library requires Java 8 or later.\n\n## Usage\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nBrandRetrieveResponse brand = client.brand().retrieve(params);\n```\n\n## Client configuration\n\nConfigure the client using system properties or environment variables:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n```\n\nOr manually:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .apiKey("My API Key")\n .build();\n```\n\nOr using a combination of the two approaches:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n // Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n // Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\n .fromEnv()\n .apiKey("My API Key")\n .build();\n```\n\nSee this table for the available options:\n\n| Setter | System property | Environment variable | Required | Default value |\n| --------- | ------------------ | -------------------- | -------- | ---------------------------- |\n| `apiKey` | `branddev.apiKey` | `BRAND_DEV_API_KEY` | true | - |\n| `baseUrl` | `branddev.baseUrl` | `BRAND_DEV_BASE_URL` | true | `"https://api.brand.dev/v1"` |\n\nSystem properties take precedence over environment variables.\n\n> [!TIP]\n> Don\'t create more than one client in the same application. Each client has a connection pool and\n> thread pools, which are more efficient to share between requests.\n\n### Modifying configuration\n\nTo temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\n\nBrandDevClient clientWithOptions = client.withOptions(optionsBuilder -> {\n optionsBuilder.baseUrl("https://example.com");\n optionsBuilder.maxRetries(42);\n});\n```\n\nThe `withOptions()` method does not affect the original client or service.\n\n## Requests and responses\n\nTo send a request to the Brand Dev API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.\n\nFor example, `client.brand().retrieve(...)` should be called with an instance of `BrandRetrieveParams`, and it will return an instance of `BrandRetrieveResponse`.\n\n## Immutability\n\nEach class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.\n\nEach class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.\n\nBecause each class is immutable, builder modification will _never_ affect already built class instances.\n\n## Asynchronous execution\n\nThe default client is synchronous. To switch to asynchronous execution, call the `async()` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClient client = BrandDevOkHttpClient.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.async().brand().retrieve(params);\n```\n\nOr create an asynchronous client from the beginning:\n\n```java\nimport com.branddev.api.client.BrandDevClientAsync;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClientAsync;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `branddev.apiKey` and `branddev.baseUrl` system properties\n// Or configures using the `BRAND_DEV_API_KEY` and `BRAND_DEV_BASE_URL` environment variables\nBrandDevClientAsync client = BrandDevOkHttpClientAsync.fromEnv();\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nCompletableFuture brand = client.brand().retrieve(params);\n```\n\nThe asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.\n\n\n\n\n\n\n\n## Raw responses\n\nThe SDK defines methods that deserialize responses into instances of Java classes. However, these methods don\'t provide access to the response headers, status code, or the raw response body.\n\nTo access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:\n\n```java\nimport com.branddev.api.core.http.Headers;\nimport com.branddev.api.core.http.HttpResponseFor;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\nHttpResponseFor brand = client.brand().withRawResponse().retrieve(params);\n\nint statusCode = brand.statusCode();\nHeaders headers = brand.headers();\n```\n\nYou can still deserialize the response into an instance of a Java class if needed:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse parsedBrand = brand.parse();\n```\n\n## Error handling\n\nThe SDK throws custom unchecked exception types:\n\n- [`BrandDevServiceException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:\n\n | Status | Exception |\n | ------ | -------------------------------------------------- |\n | 400 | [`BadRequestException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BadRequestException.kt) |\n | 401 | [`UnauthorizedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnauthorizedException.kt) |\n | 403 | [`PermissionDeniedException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/PermissionDeniedException.kt) |\n | 404 | [`NotFoundException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/NotFoundException.kt) |\n | 422 | [`UnprocessableEntityException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnprocessableEntityException.kt) |\n | 429 | [`RateLimitException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/RateLimitException.kt) |\n | 5xx | [`InternalServerException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/InternalServerException.kt) |\n | others | [`UnexpectedStatusCodeException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/UnexpectedStatusCodeException.kt) |\n\n- [`BrandDevIoException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevIoException.kt): I/O networking errors.\n\n- [`BrandDevRetryableException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevRetryableException.kt): Generic error indicating a failure that could be retried by the client.\n\n- [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that\'s supposed to be required, but the API unexpectedly omitted it from the response.\n\n- [`BrandDevException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.\n\n\n\n## Logging\n\nEnable logging by setting the `BRAND_DEV_LOG` environment variable to `info`:\n\n```sh\nexport BRAND_DEV_LOG=info\n```\n\nOr to `debug` for more verbose logging:\n\n```sh\nexport BRAND_DEV_LOG=debug\n```\n\nOr configure the client manually using the `logLevel` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.core.LogLevel;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .logLevel(LogLevel.INFO)\n .build();\n```\n\n## ProGuard and R8\n\nAlthough the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `brand-dev-java-core` is published with a [configuration file](brand-dev-java-core/src/main/resources/META-INF/proguard/brand-dev-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).\n\nProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.\n\n\n\n\n\n## Jackson\n\nThe SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.\n\nThe SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).\n\nIf the SDK threw an exception, but you\'re _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt).\n\n> [!CAUTION]\n> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.\n\nAlso note that there are bugs in older Jackson versions that can affect the SDK. We don\'t work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead.\n\n## Network options\n\n### Retries\n\nThe SDK automatically retries 2 times by default, with a short exponential backoff between requests.\n\nOnly the following error types are retried:\n- Connection errors (for example, due to a network connectivity problem)\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- 5xx Internal\n\nThe API may also explicitly instruct the SDK to retry or not retry a request.\n\nTo set a custom number of retries, configure the client using the `maxRetries` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .maxRetries(4)\n .build();\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default.\n\nTo set a custom timeout, configure the method call using the `timeout` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .timeout(Duration.ofSeconds(30))\n .build();\n```\n\n### Proxies\n\nTo route requests through a proxy, configure the client using the `proxy` method:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(new Proxy(\n Proxy.Type.HTTP, new InetSocketAddress(\n "https://example.com", 8080\n )\n ))\n .build();\n```\n\nIf the proxy responds with `407 Proxy Authentication Required`, supply credentials by also configuring `proxyAuthenticator`:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport com.branddev.api.core.http.ProxyAuthenticator;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .proxy(...)\n // Or a custom implementation of `ProxyAuthenticator`.\n .proxyAuthenticator(ProxyAuthenticator.basic("username", "password"))\n .build();\n```\n\n### Connection pooling\n\nTo customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\nimport java.time.Duration;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.\n .maxIdleConnections(10)\n .keepAliveDuration(Duration.ofMinutes(2))\n .build();\n```\n\nIf both options are unset, OkHttp\'s default connection pool settings are used.\n\n### HTTPS\n\n> [!NOTE]\n> Most applications should not call these methods, and instead use the system defaults. The defaults include\n> special optimizations that can be lost if the implementations are modified.\n\nTo configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.\n .sslSocketFactory(yourSSLSocketFactory)\n .trustManager(yourTrustManager)\n .hostnameVerifier(yourHostnameVerifier)\n .build();\n```\n\n\n\n### Custom HTTP client\n\nThe SDK consists of three artifacts:\n- `brand-dev-java-core`\n - Contains core SDK logic\n - Does not depend on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClient.kt), [`BrandDevClientAsync`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsync.kt), [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt), and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), all of which can work with any HTTP client\n- `brand-dev-java-client-okhttp`\n - Depends on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) and [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), which provide a way to construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) and [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), respectively, using OkHttp\n- `brand-dev-java`\n - Depends on and exposes the APIs of both `brand-dev-java-core` and `brand-dev-java-client-okhttp`\n - Does not have its own logic\n\nThis structure allows replacing the SDK\'s default HTTP client without pulling in unnecessary dependencies.\n\n#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)\n\n> [!TIP]\n> Try the available [network options](#network-options) before replacing the default client.\n\nTo use a customized `OkHttpClient`:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Copy `brand-dev-java-client-okhttp`\'s [`OkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/OkHttpClient.kt) class into your code and customize it\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your customized client\n\n### Completely custom HTTP client\n\nTo use a completely custom HTTP client:\n\n1. Replace your [`brand-dev-java` dependency](#installation) with `brand-dev-java-core`\n2. Write a class that implements the [`HttpClient`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/http/HttpClient.kt) interface\n3. Construct [`BrandDevClientImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientImpl.kt) or [`BrandDevClientAsyncImpl`](brand-dev-java-core/src/main/kotlin/com/branddev/api/client/BrandDevClientAsyncImpl.kt), similarly to [`BrandDevOkHttpClient`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClient.kt) or [`BrandDevOkHttpClientAsync`](brand-dev-java-client-okhttp/src/main/kotlin/com/branddev/api/client/okhttp/BrandDevOkHttpClientAsync.kt), using your new client class\n\n## Undocumented API functionality\n\nThe SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.\n\n### Parameters\n\nTo set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .putAdditionalHeader("Secret-Header", "42")\n .putAdditionalQueryParam("secret_query_param", "42")\n .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))\n .build();\n```\n\nThese can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.\n\nTo set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport com.branddev.api.models.brand.BrandAiQueryParams;\n\nBrandAiQueryParams params = BrandAiQueryParams.builder()\n .specificPages(BrandAiQueryParams.SpecificPages.builder()\n .putAdditionalProperty("secretProperty", JsonValue.from("42"))\n .build())\n .build();\n```\n\nThese properties can be accessed on the nested built object later using the `_additionalProperties()` method.\n\nTo set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) object to its setter:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain("REPLACE_ME")\n .build();\n```\n\nThe most straightforward way to create a [`JsonValue`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt) is using its `from(...)` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.List;\nimport java.util.Map;\n\n// Create primitive JSON values\nJsonValue nullValue = JsonValue.from(null);\nJsonValue booleanValue = JsonValue.from(true);\nJsonValue numberValue = JsonValue.from(42);\nJsonValue stringValue = JsonValue.from("Hello World!");\n\n// Create a JSON array value equivalent to `["Hello", "World"]`\nJsonValue arrayValue = JsonValue.from(List.of(\n "Hello", "World"\n));\n\n// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`\nJsonValue objectValue = JsonValue.from(Map.of(\n "a", 1,\n "b", 2\n));\n\n// Create an arbitrarily nested JSON equivalent to:\n// {\n// "a": [1, 2],\n// "b": [3, 4]\n// }\nJsonValue complexValue = JsonValue.from(Map.of(\n "a", List.of(\n 1, 2\n ),\n "b", List.of(\n 3, 4\n )\n));\n```\n\nNormally a `Builder` class\'s `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.\n\nTo forcibly omit a required parameter or property, pass [`JsonMissing`](brand-dev-java-core/src/main/kotlin/com/branddev/api/core/Values.kt):\n\n```java\nimport com.branddev.api.core.JsonMissing;\nimport com.branddev.api.models.brand.BrandRetrieveParams;\n\nBrandRetrieveParams params = BrandRetrieveParams.builder()\n .domain(JsonMissing.of())\n .build();\n```\n\n### Response properties\n\nTo access undocumented response properties, call the `_additionalProperties()` method:\n\n```java\nimport com.branddev.api.core.JsonValue;\nimport java.util.Map;\n\nMap additionalProperties = client.brand().retrieve(params)._additionalProperties();\nJsonValue secretPropertyValue = additionalProperties.get("secretProperty");\n\nString result = secretPropertyValue.accept(new JsonValue.Visitor<>() {\n @Override\n public String visitNull() {\n return "It\'s null!";\n }\n\n @Override\n public String visitBoolean(boolean value) {\n return "It\'s a boolean!";\n }\n\n @Override\n public String visitNumber(Number value) {\n return "It\'s a number!";\n }\n\n // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`\n // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden\n});\n```\n\nTo access a property\'s raw JSON value, which may be undocumented, call its `_` prefixed method:\n\n```java\nimport com.branddev.api.core.JsonField;\nimport java.util.Optional;\n\nJsonField field = client.brand().retrieve(params)._field();\n\nif (field.isMissing()) {\n // The property is absent from the JSON response\n} else if (field.isNull()) {\n // The property was set to literal null\n} else {\n // Check if value was provided as a string\n // Other methods include `asNumber()`, `asBoolean()`, etc.\n Optional jsonString = field.asString();\n\n // Try to deserialize into a custom type\n MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class);\n}\n```\n\n### Response validation\n\nIn rare cases, the API may return a response that doesn\'t match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.\n\nBy default, the SDK will not throw an exception in this case. It will throw [`BrandDevInvalidDataException`](brand-dev-java-core/src/main/kotlin/com/branddev/api/errors/BrandDevInvalidDataException.kt) only if you directly access the property.\n\nValidating the response is _not_ forwards compatible with new types from the API for existing fields.\n\nIf you would still prefer to check that the response is completely well-typed upfront, then either call `validate()`:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(params).validate();\n```\n\nOr configure the method call to validate the response using the `responseValidation` method:\n\n```java\nimport com.branddev.api.models.brand.BrandRetrieveResponse;\n\nBrandRetrieveResponse brand = client.brand().retrieve(\n params, RequestOptions.builder().responseValidation(true).build()\n);\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.branddev.api.client.BrandDevClient;\nimport com.branddev.api.client.okhttp.BrandDevOkHttpClient;\n\nBrandDevClient client = BrandDevOkHttpClient.builder()\n .fromEnv()\n .responseValidation(true)\n .build();\n```\n\n## FAQ\n\n### Why don\'t you use plain `enum` classes?\n\nJava `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.\n\n### Why do you represent fields using `JsonField` instead of just plain `T`?\n\nUsing `JsonField` enables a few features:\n\n- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)\n- Lazily [validating the API response against the expected shape](#response-validation)\n- Representing absent vs explicitly null values\n\n### Why don\'t you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?\n\nIt is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don\'t want to introduce a breaking change every time we add a field to a class.\n\n### Why don\'t you use checked exceptions?\n\nChecked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.\n\nChecked exceptions:\n\n- Are verbose to handle\n- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error\n- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)\n- Don\'t play well with lambdas (also due to the function coloring problem)\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/context-dot-dev/deprecated-brand-java-sdk/issues) with questions, bugs, or suggestions.\n', }, { language: 'python', From 2ab340e31211d77b67bd67dd1caffa1af2aa9be5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 04:37:39 +0000 Subject: [PATCH 057/100] chore: redact api-key headers in debug logs --- src/internal/utils/log.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index bc741a94..83eb3815 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -107,6 +107,8 @@ export const formatRequestDetails = (details: { name, ( name.toLowerCase() === 'authorization' || + name.toLowerCase() === 'api-key' || + name.toLowerCase() === 'x-api-key' || name.toLowerCase() === 'cookie' || name.toLowerCase() === 'set-cookie' ) ? From 43869b83724b01e5e28a1b23f179633f3760f74b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 9 May 2026 01:35:51 +0000 Subject: [PATCH 058/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 9 ++++++--- src/resources/brand.ts | 18 ++++++++++++++++++ tests/api-resources/brand.test.ts | 3 +++ 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3647616d..7d8efa93 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-f930a89f5fccd44dd6548fce8ae69ab2d966dd10a3e3dfa128a8894089a34d1a.yml -openapi_spec_hash: d21ebf5fac677f08d74a9153fb57f9af +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-1e7156456cea5c8586e6e3b189d0477cb84176c9d5ff3c2dce4baee36137fe8b.yml +openapi_spec_hash: a5e97fe34f248eb0927baf52debaf79a config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 2e1964f6..42548e8f 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -597,10 +597,11 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'maxAgeMs?: number;', 'parsePDF?: boolean;', 'timeoutMS?: number;', + 'waitForMs?: number;', ], response: '{ html: string; success: true; url: string; }', markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, includeFrames?: boolean, maxAgeMs?: number, parsePDF?: boolean, timeoutMS?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and returned wrapped in . When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\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- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, includeFrames?: boolean, maxAgeMs?: number, parsePDF?: boolean, timeoutMS?: number, waitForMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and returned wrapped in . When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', @@ -646,10 +647,11 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'shortenBase64Images?: boolean;', 'timeoutMS?: number;', 'useMainContentOnly?: boolean;', + 'waitForMs?: number;', ], response: '{ markdown: string; success: true; url: string; }', markdown: - "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, parsePDF?: boolean, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and converted to Markdown. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, parsePDF?: boolean, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and converted to Markdown. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeMd', @@ -691,11 +693,12 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; };', 'maxAgeMs?: number;', 'timeoutMS?: number;', + 'waitForMs?: number;', ], response: "{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }", markdown: - "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number, timeoutMS?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\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- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number, timeoutMS?: number, waitForMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\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 before collecting images. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeImages', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 9a2130b4..b3bd7ae8 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -7076,6 +7076,12 @@ export interface BrandWebScrapeHTMLParams { * value is 300000ms (5 minutes). */ timeoutMS?: number; + + /** + * Optional browser wait time in milliseconds after initial page load. Min: 0. Max: + * 30000 (30 seconds). + */ + waitForMs?: number; } export interface BrandWebScrapeImagesParams { @@ -7102,6 +7108,12 @@ export interface BrandWebScrapeImagesParams { * value is 300000ms (5 minutes). */ timeoutMS?: number; + + /** + * Optional browser wait time in milliseconds after initial page load before + * collecting images. Min: 0. Max: 30000 (30 seconds). + */ + waitForMs?: number; } export namespace BrandWebScrapeImagesParams { @@ -7186,6 +7198,12 @@ export interface BrandWebScrapeMdParams { * and navigation */ useMainContentOnly?: boolean; + + /** + * Optional browser wait time in milliseconds after initial page load before + * converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). + */ + waitForMs?: number; } export interface BrandWebScrapeSitemapParams { diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index e330635c..67a21d39 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -321,6 +321,7 @@ describe('resource brand', () => { maxAgeMs: 0, parsePDF: true, timeoutMS: 1000, + waitForMs: 0, }); }); @@ -348,6 +349,7 @@ describe('resource brand', () => { }, maxAgeMs: 0, timeoutMS: 1000, + waitForMs: 0, }); }); @@ -375,6 +377,7 @@ describe('resource brand', () => { shortenBase64Images: true, timeoutMS: 1000, useMainContentOnly: true, + waitForMs: 0, }); }); From 1b700bfe47a384d90c945b5d6e02509d665dd0fb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 10 May 2026 16:07:03 +0000 Subject: [PATCH 059/100] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 8 +-- src/resources/brand.ts | 64 +++++++++++++++++--- tests/api-resources/brand.test.ts | 12 +++- 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7d8efa93..dd6dd370 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-1e7156456cea5c8586e6e3b189d0477cb84176c9d5ff3c2dce4baee36137fe8b.yml -openapi_spec_hash: a5e97fe34f248eb0927baf52debaf79a +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-2ed135a665bd4f01ec462096a6e19597f06356121646256cee090d1156fbfd45.yml +openapi_spec_hash: 03039640f82e64d738a57f3d3af4445e config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 42548e8f..0178093f 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -595,13 +595,13 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'url: string;', 'includeFrames?: boolean;', 'maxAgeMs?: number;', - 'parsePDF?: boolean;', + 'pdf?: { end?: number; shouldParse?: boolean; start?: number; };', 'timeoutMS?: number;', 'waitForMs?: number;', ], response: '{ html: string; success: true; url: string; }', markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, includeFrames?: boolean, maxAgeMs?: number, parsePDF?: boolean, timeoutMS?: number, waitForMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and returned wrapped in . When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, includeFrames?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, waitForMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', @@ -643,7 +643,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'includeImages?: boolean;', 'includeLinks?: boolean;', 'maxAgeMs?: number;', - 'parsePDF?: boolean;', + 'pdf?: { end?: number; shouldParse?: boolean; start?: number; };', 'shortenBase64Images?: boolean;', 'timeoutMS?: number;', 'useMainContentOnly?: boolean;', @@ -651,7 +651,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ ], response: '{ markdown: string; success: true; url: string; }', markdown: - "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, parsePDF?: boolean, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `parsePDF?: boolean`\n When true (default), PDF URLs are fetched and their text layer is extracted and converted to Markdown. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeMd', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index b3bd7ae8..ef44c376 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -7064,11 +7064,10 @@ export interface BrandWebScrapeHTMLParams { maxAgeMs?: number; /** - * When true (default), PDF URLs are fetched and their text layer is extracted and - * returned wrapped in . When false, PDF URLs are skipped - * and a 400 WEBSITE_ACCESS_ERROR is returned. + * PDF parsing controls. Use start/end to limit text extraction and OCR to an + * inclusive 1-based page range. */ - parsePDF?: boolean; + pdf?: BrandWebScrapeHTMLParams.Pdf; /** * Optional timeout in milliseconds for the request. If the request takes longer @@ -7084,6 +7083,31 @@ export interface BrandWebScrapeHTMLParams { waitForMs?: number; } +export namespace BrandWebScrapeHTMLParams { + /** + * PDF parsing controls. Use start/end to limit text extraction and OCR to an + * inclusive 1-based page range. + */ + export interface Pdf { + /** + * 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. + */ + end?: number; + + /** + * When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and + * a 400 WEBSITE_ACCESS_ERROR is returned. + */ + shouldParse?: boolean; + + /** + * First 1-based PDF page to parse. When omitted, parsing starts at the first page. + */ + start?: number; + } +} + export interface BrandWebScrapeImagesParams { /** * Page URL to inspect. Must include http:// or https://. @@ -7175,11 +7199,10 @@ export interface BrandWebScrapeMdParams { maxAgeMs?: number; /** - * When true (default), PDF URLs are fetched and their text layer is extracted and - * converted to Markdown. When false, PDF URLs are skipped and a 400 - * WEBSITE_ACCESS_ERROR is returned. + * PDF parsing controls. Use start/end to limit text extraction and OCR to an + * inclusive 1-based page range. */ - parsePDF?: boolean; + pdf?: BrandWebScrapeMdParams.Pdf; /** * Shorten base64-encoded image data in the Markdown output @@ -7206,6 +7229,31 @@ export interface BrandWebScrapeMdParams { waitForMs?: number; } +export namespace BrandWebScrapeMdParams { + /** + * PDF parsing controls. Use start/end to limit text extraction and OCR to an + * inclusive 1-based page range. + */ + export interface Pdf { + /** + * 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. + */ + end?: number; + + /** + * When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and + * a 400 WEBSITE_ACCESS_ERROR is returned. + */ + shouldParse?: boolean; + + /** + * First 1-based PDF page to parse. When omitted, parsing starts at the first page. + */ + start?: number; + } +} + export interface BrandWebScrapeSitemapParams { /** * Domain to build a sitemap for diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 67a21d39..3a2976db 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -319,7 +319,11 @@ describe('resource brand', () => { url: 'https://example.com', includeFrames: true, maxAgeMs: 0, - parsePDF: true, + pdf: { + end: 1, + shouldParse: true, + start: 1, + }, timeoutMS: 1000, waitForMs: 0, }); @@ -373,7 +377,11 @@ describe('resource brand', () => { includeImages: true, includeLinks: true, maxAgeMs: 0, - parsePDF: true, + pdf: { + end: 1, + shouldParse: true, + start: 1, + }, shortenBase64Images: true, timeoutMS: 1000, useMainContentOnly: true, From 5ba74ed49659bd1340ad0a07ace953ca3ca65481 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 01:42:23 +0000 Subject: [PATCH 060/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index dd6dd370..decd7711 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-2ed135a665bd4f01ec462096a6e19597f06356121646256cee090d1156fbfd45.yml -openapi_spec_hash: 03039640f82e64d738a57f3d3af4445e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-9d3ae65f98566401c376518084a07e8ff20ecd2742b26b82ba72b35f63c6b6ca.yml +openapi_spec_hash: bc97527ca3317e0665ed1bf48caf85c8 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From c286fccb2405096eccd50a1c9c2a48ca3663654a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 11 May 2026 01:46:47 +0000 Subject: [PATCH 061/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index decd7711..b047dd65 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-9d3ae65f98566401c376518084a07e8ff20ecd2742b26b82ba72b35f63c6b6ca.yml -openapi_spec_hash: bc97527ca3317e0665ed1bf48caf85c8 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-1a6ed1d226f13ac921b4cc545f03accce635e59b7b3150b12cc7d53d262e513d.yml +openapi_spec_hash: 9c0246fcd737ffd9c984d4e9ebc64736 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 5b702cf6cb2db09d510615b91b30527279fa15f1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 02:57:18 +0000 Subject: [PATCH 062/100] ci: pin GitHub Actions to commit SHAs Pin all GitHub Actions referenced in generated workflows (both first-party `actions/*` and third-party) to immutable commit SHAs. Updating pinned actions is now a deliberate codegen-side bump rather than implicit on every workflow run. --- .github/workflows/ci.yml | 14 +++++++------- .github/workflows/publish-npm.yml | 4 ++-- .github/workflows/release-doctor.yml | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8125850d..9e9b6f07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,10 +21,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/brand.dev-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' @@ -43,10 +43,10 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' @@ -61,7 +61,7 @@ jobs: github.repository == 'stainless-sdks/brand.dev-typescript' && !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: core.setOutput('github_token', await core.getIDToken()); @@ -91,10 +91,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/brand.dev-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 27223ca5..57aa7670 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -21,10 +21,10 @@ jobs: id-token: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1 with: node-version: '20' diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 0c860c4a..039dbf90 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'context-dot-dev/deprecated-brand-typescript-sdk' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check release environment run: | From b299ebb81a8056f1451e731d3893a2e4d85bf525 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 16:26:15 +0000 Subject: [PATCH 063/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b047dd65..7381cdd3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-1a6ed1d226f13ac921b4cc545f03accce635e59b7b3150b12cc7d53d262e513d.yml -openapi_spec_hash: 9c0246fcd737ffd9c984d4e9ebc64736 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-12e9deaf43f690da9fa9319d4e93e4f8f6184e09badcc83e2b1f0c4891cf6ce3.yml +openapi_spec_hash: b18735a3f4c73c37fbb60515c9b8c346 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 5513a490b28c753286ead83ae4b3f878819c5d67 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 16:50:53 +0000 Subject: [PATCH 064/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7381cdd3..5f9bc778 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-12e9deaf43f690da9fa9319d4e93e4f8f6184e09badcc83e2b1f0c4891cf6ce3.yml -openapi_spec_hash: b18735a3f4c73c37fbb60515c9b8c346 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-ea848da22c7fabe9073064f70f12a618993846ecc5dfedbc24a0326b9f1f6fdb.yml +openapi_spec_hash: 284bb75c275d0084eb650847c4076fe4 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 13590ab1e17b3176c3d6a6f0a35663f6af49dfcd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 17:12:55 +0000 Subject: [PATCH 065/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5f9bc778..b034d58e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-ea848da22c7fabe9073064f70f12a618993846ecc5dfedbc24a0326b9f1f6fdb.yml -openapi_spec_hash: 284bb75c275d0084eb650847c4076fe4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-5cf59db203bea5af40ea44e7ffc26b503361856a760e997da46e64528dd15b46.yml +openapi_spec_hash: a1273d28c2439dae91074a21b866740c config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From aa86b8148409bb59b2814f4a2e17f148c81bed7b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 17:21:31 +0000 Subject: [PATCH 066/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b034d58e..1d491ca6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-5cf59db203bea5af40ea44e7ffc26b503361856a760e997da46e64528dd15b46.yml -openapi_spec_hash: a1273d28c2439dae91074a21b866740c +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-cce6310a59a9676fe3aad74b5a24bbc5f1899767b71b3c912e34d50496d2d03f.yml +openapi_spec_hash: 9e97e5d4745c4fdbbc3269e9013d4094 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 16509b726541f4de5aa89d5ef40647abd84c9dde Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 02:53:23 +0000 Subject: [PATCH 067/100] chore(tests): remove redundant File import --- tests/uploads.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index 1a569976..96fb9598 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,7 +1,6 @@ import fs from 'fs'; import type { ResponseLike } from 'brand.dev/internal/to-file'; import { toFile } from 'brand.dev/core/uploads'; -import { File } from 'node:buffer'; class MyClass { name: string = 'foo'; From e85a50ac5ef776a655b7cd7a1375a8ce634d1e4b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 02:53:57 +0000 Subject: [PATCH 068/100] fix(typescript): upgrade tsc-multi so that it works with Node 26 --- package.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/yarn.lock | 6 +++--- yarn.lock | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 22c619e3..7616a769 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "publint": "^0.2.12", "ts-jest": "^29.1.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "tslib": "^2.8.1", "typescript": "5.8.3", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index d8cec012..18cfcea4 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -74,7 +74,7 @@ "ts-jest": "^29.1.0", "ts-morph": "^19.0.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz", "tsconfig-paths": "^4.0.0" }, "imports": { diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock index c7e37692..c6b17b02 100644 --- a/packages/mcp-server/yarn.lock +++ b/packages/mcp-server/yarn.lock @@ -3921,9 +3921,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz": - version "1.1.9" - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz#777f6f5d9e26bf0e94e5170990dd3a841d6707cd" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz": + version "1.1.11" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz#010247051be13b55abdc98f787c017285149f4f2" dependencies: debug "^4.3.7" fast-glob "^3.3.2" diff --git a/yarn.lock b/yarn.lock index 18e7cbdc..00842e32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3192,9 +3192,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.0" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz": - version "1.1.9" - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz#777f6f5d9e26bf0e94e5170990dd3a841d6707cd" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz": + version "1.1.11" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz#010247051be13b55abdc98f787c017285149f4f2" dependencies: debug "^4.3.7" fast-glob "^3.3.2" From 59b5f95b896846a31c9c7852337f125ae65439e3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 14:27:05 +0000 Subject: [PATCH 069/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 4 ++-- src/resources/brand.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1d491ca6..18913099 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-cce6310a59a9676fe3aad74b5a24bbc5f1899767b71b3c912e34d50496d2d03f.yml -openapi_spec_hash: 9e97e5d4745c4fdbbc3269e9013d4094 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-1bc9121ee0f64a15a503b5ec2a7836edfb1e2bf561d22f598ff3cf8f40381a9c.yml +openapi_spec_hash: e4980adb7bd8a6a37a1dbb7f35585b79 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 0178093f..de030dae 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -685,7 +685,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ httpMethod: 'get', summary: 'Scrape Images', description: - 'Extract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.', + 'Extract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit. When enrichment is enabled, the entire call costs 5 credits.', stainlessPath: '(resource) brand > (method) web_scrape_images', qualified: 'client.brand.webScrapeImages', params: [ @@ -698,7 +698,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }", markdown: - "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number, timeoutMS?: number, waitForMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit; enrichment costs 1 credit per returned image.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\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 before collecting images. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number, timeoutMS?: number, waitForMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit. When enrichment is enabled, the entire call costs 5 credits.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\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 before collecting images. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeImages', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index ef44c376..242bb221 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -139,8 +139,8 @@ export class Brand extends APIResource { /** * Extract image assets from a web page, including standard URLs, inline SVGs, data * URIs, responsive image sources, metadata, CSS backgrounds, video posters, and - * embeds. The base request costs 1 credit; enrichment costs 1 credit per returned - * image. + * embeds. The base request costs 1 credit. When enrichment is enabled, the entire + * call costs 5 credits. */ webScrapeImages( query: BrandWebScrapeImagesParams, From b3bf84fcb2fc398edf72f1ff5f3649eab37212ee Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 25 May 2026 17:39:04 +0000 Subject: [PATCH 070/100] feat(api): api update --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 00842e32..06fc1085 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1215,9 +1215,9 @@ baseline-browser-mapping@^2.9.0: integrity sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg== brace-expansion@^2.0.2: - version "2.1.0" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.0.tgz#4f41a41190216ee36067ec381526fe9539c4f0ae" - integrity sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w== + version "2.1.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.1.tgz#c68b1c4111c76aae3a6fba55d496cee10c39dad8" + integrity sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA== dependencies: balanced-match "^1.0.0" From 4e7a0408c41c57ac35ee99e820d2caf0d6c1b0ea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 02:43:24 +0000 Subject: [PATCH 071/100] fix(mcp): use `pure-lockfile` when building mcp server --- scripts/build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build b/scripts/build index c310f9b9..35b052d3 100755 --- a/scripts/build +++ b/scripts/build @@ -52,6 +52,6 @@ fi # build all sub-packages for dir in packages/*; do if [ -d "$dir" ]; then - (cd "$dir" && yarn install && yarn build) + (cd "$dir" && yarn install --pure-lockfile && yarn build) fi done From fec09545c6cccc8875021e2d357c67c2e3cc7a1a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 30 May 2026 18:04:42 +0000 Subject: [PATCH 072/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 18913099..a6a8eef5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-1bc9121ee0f64a15a503b5ec2a7836edfb1e2bf561d22f598ff3cf8f40381a9c.yml -openapi_spec_hash: e4980adb7bd8a6a37a1dbb7f35585b79 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-0b3011817c67eccaecd7deffad948f2fcd5408a04c584c3de83d69129e8bbea9.yml +openapi_spec_hash: a35cd63ce6fc1124b4ef13f63e7e29cb config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From d7364dc0797c8fb3b5161ea671004c6299b5253d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 19:16:31 +0000 Subject: [PATCH 073/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a6a8eef5..81725ad4 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-0b3011817c67eccaecd7deffad948f2fcd5408a04c584c3de83d69129e8bbea9.yml -openapi_spec_hash: a35cd63ce6fc1124b4ef13f63e7e29cb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-f17d27c370b0b4d6ac476ac3b6bdfcb099c7c877d7f9de5e170219601dac00ba.yml +openapi_spec_hash: 89afb32832b6c8768d0150089a026e1b config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 5f9930ad23c3cd465151007f9d4a7c90f0b09c02 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 20:16:11 +0000 Subject: [PATCH 074/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 81725ad4..b9027d8f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-f17d27c370b0b4d6ac476ac3b6bdfcb099c7c877d7f9de5e170219601dac00ba.yml -openapi_spec_hash: 89afb32832b6c8768d0150089a026e1b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-10ec1bc74f69831a4fbc461c6defa14030681cbeebb351760fe8e5ce5d1c3421.yml +openapi_spec_hash: 393bb6cb95846763248d6f737271e653 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 5d36f06c68d8c4596de5d74f987b14b10e4dc426 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 21:54:28 +0000 Subject: [PATCH 075/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b9027d8f..12206a6f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-10ec1bc74f69831a4fbc461c6defa14030681cbeebb351760fe8e5ce5d1c3421.yml -openapi_spec_hash: 393bb6cb95846763248d6f737271e653 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-c534e82e2da624a7c3d9843652132db3791a91eef51c777d039e23e3d45f1ece.yml +openapi_spec_hash: 4c260d71b003474c4d29754cf928fc2d config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 7d2b2a7cecffa48f9f5f505b8ac9dea821fa4fcc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 23:16:39 +0000 Subject: [PATCH 076/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 12206a6f..049c6727 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-c534e82e2da624a7c3d9843652132db3791a91eef51c777d039e23e3d45f1ece.yml -openapi_spec_hash: 4c260d71b003474c4d29754cf928fc2d +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-e432c523efb3bfd0f768b85458c715480ce33b2289b1505971819502e72a220c.yml +openapi_spec_hash: ddef4e7240549c27374c98bac65a44da config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 5a147fa6a2350cc157d8ba9db10a569b5843f23f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 02:49:29 +0000 Subject: [PATCH 077/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 049c6727..38438188 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-e432c523efb3bfd0f768b85458c715480ce33b2289b1505971819502e72a220c.yml -openapi_spec_hash: ddef4e7240549c27374c98bac65a44da +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-e4447a53f29d624f1458d2d56b406e12b124333eda14bb67aa6497d7bbf1e705.yml +openapi_spec_hash: df5979d99fd7c4e6546c5dadcbd47b5e config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From bda58a21fefd3e9c78a0263d1d545ada3ce0a01d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:02:41 +0000 Subject: [PATCH 078/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 38438188..f805046d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-e4447a53f29d624f1458d2d56b406e12b124333eda14bb67aa6497d7bbf1e705.yml -openapi_spec_hash: df5979d99fd7c4e6546c5dadcbd47b5e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-86ee5da44d1b12e8bda41916b716e48f4c7634c539bef7bf5335f55a34616ac8.yml +openapi_spec_hash: d8c32416241035412c6b07aab88395cb config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 4f0d5a2cc2cecb7e86f8cc353879fbfd9422dfff Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 10:43:49 +0000 Subject: [PATCH 079/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f805046d..41f55e40 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-86ee5da44d1b12e8bda41916b716e48f4c7634c539bef7bf5335f55a34616ac8.yml -openapi_spec_hash: d8c32416241035412c6b07aab88395cb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-19f8905993677bfe20e73de262153f3ff68507ed685031d1514f76eaca40cd06.yml +openapi_spec_hash: d36d3ca40ef653a89660b2967d6f592e config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 17ac6db9ee4a0e1a51db6b57bad90774212694d2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:05:56 +0000 Subject: [PATCH 080/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 41f55e40..bc82c92d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-19f8905993677bfe20e73de262153f3ff68507ed685031d1514f76eaca40cd06.yml -openapi_spec_hash: d36d3ca40ef653a89660b2967d6f592e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-2fd1d538ce72b2e2a8cc6ab0d00638b30c2c156e5cf273d91ba6618564b2a696.yml +openapi_spec_hash: a1ba1d14a1e783d5d494d95a9188e710 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From e3c35b205dcf4fa35dc398821cef929a469f04eb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:09:13 +0000 Subject: [PATCH 081/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index bc82c92d..2b9672e0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-2fd1d538ce72b2e2a8cc6ab0d00638b30c2c156e5cf273d91ba6618564b2a696.yml -openapi_spec_hash: a1ba1d14a1e783d5d494d95a9188e710 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-141a124a7556308d98115f190fc73a433ab39286ebad780604f8eb076ca23e48.yml +openapi_spec_hash: 434ca3f02912e54b70d3c85f3e317954 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 5d0ba359871125bbda7aa1f87b114009e1f9d864 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:55:08 +0000 Subject: [PATCH 082/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2b9672e0..4c459027 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-141a124a7556308d98115f190fc73a433ab39286ebad780604f8eb076ca23e48.yml -openapi_spec_hash: 434ca3f02912e54b70d3c85f3e317954 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-68b097a33ef54d278ffead558342d6dde258f1f42ce5f74d8cff16b925dd5510.yml +openapi_spec_hash: bb9c40c477e932de35d100f4e0e85b3e config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 2e168c3fe448d14473ca3fc977f3559f8ddbfe1f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 14:07:37 +0000 Subject: [PATCH 083/100] feat(api): api update --- .stats.yml | 4 +-- packages/mcp-server/src/local-docs-search.ts | 19 +++++++++---- src/resources/brand.ts | 28 ++++++++++++++++++++ tests/api-resources/brand.test.ts | 4 +++ 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4c459027..a162a040 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-68b097a33ef54d278ffead558342d6dde258f1f42ce5f74d8cff16b925dd5510.yml -openapi_spec_hash: bb9c40c477e932de35d100f4e0e85b3e +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-6ed467d40802bbe92c036743ad980f3cb986626e18a8e3b743e05382eee00b97.yml +openapi_spec_hash: 5fb10c717fc138f1202f8395b37713db config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index de030dae..f331763c 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -593,6 +593,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.webScrapeHTML', params: [ 'url: string;', + 'headers?: object;', 'includeFrames?: boolean;', 'maxAgeMs?: number;', 'pdf?: { end?: number; shouldParse?: boolean; start?: number; };', @@ -601,7 +602,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ ], response: '{ html: string; success: true; url: string; }', markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, includeFrames?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, waitForMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, headers?: object, includeFrames?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, waitForMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', @@ -639,6 +640,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.webScrapeMd', params: [ 'url: string;', + 'headers?: object;', 'includeFrames?: boolean;', 'includeImages?: boolean;', 'includeLinks?: boolean;', @@ -651,7 +653,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ ], response: '{ markdown: string; success: true; url: string; }', markdown: - "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, headers?: object, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeMd', @@ -691,6 +693,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ params: [ 'url: string;', 'enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; };', + 'headers?: object;', 'maxAgeMs?: number;', 'timeoutMS?: number;', 'waitForMs?: number;', @@ -698,7 +701,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }", markdown: - "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, maxAgeMs?: number, timeoutMS?: number, waitForMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit. When enrichment is enabled, the entire call costs 5 credits.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\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 before collecting images. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, headers?: object, maxAgeMs?: number, timeoutMS?: number, waitForMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit. When enrichment is enabled, the entire call costs 5 credits.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\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 before collecting images. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeImages', @@ -734,11 +737,17 @@ const EMBEDDED_METHODS: MethodEntry[] = [ description: "Crawl an entire website's sitemap and return all discovered page URLs.", stainlessPath: '(resource) brand > (method) web_scrape_sitemap', qualified: 'client.brand.webScrapeSitemap', - params: ['domain: string;', 'maxLinks?: number;', 'timeoutMS?: number;', 'urlRegex?: string;'], + params: [ + 'domain: string;', + 'headers?: object;', + 'maxLinks?: number;', + 'timeoutMS?: number;', + 'urlRegex?: string;', + ], response: '{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }', markdown: - "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, maxLinks?: number, timeoutMS?: number, urlRegex?: string): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\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 Optional RE2-compatible regex pattern. Only URLs matching this pattern are returned and counted against maxLinks.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, headers?: object, maxLinks?: number, timeoutMS?: number, urlRegex?: string): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\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 Optional RE2-compatible regex pattern. Only URLs matching this pattern are returned and counted against maxLinks.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeSitemap', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 242bb221..dae0bf11 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -7051,6 +7051,13 @@ export interface BrandWebScrapeHTMLParams { */ url: string; + /** + * Optional outbound HTTP headers forwarded only to the target URL, sent as + * deep-object query params such as headers[X-Custom]=value. When provided, caching + * is bypassed: the result is neither read from nor written to cache. + */ + headers?: { [key: string]: string }; + /** * When true, iframes are rendered inline into the returned HTML. */ @@ -7120,6 +7127,13 @@ export interface BrandWebScrapeImagesParams { */ enrichment?: BrandWebScrapeImagesParams.Enrichment; + /** + * Optional outbound HTTP headers forwarded only to the target URL, sent as + * deep-object query params such as headers[X-Custom]=value. When provided, caching + * is bypassed: the result is neither read from nor written to cache. + */ + headers?: { [key: string]: string }; + /** * Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 * day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days). @@ -7176,6 +7190,13 @@ export interface BrandWebScrapeMdParams { */ url: string; + /** + * Optional outbound HTTP headers forwarded only to the target URL, sent as + * deep-object query params such as headers[X-Custom]=value. When provided, caching + * is bypassed: the result is neither read from nor written to cache. + */ + headers?: { [key: string]: string }; + /** * When true, the contents of iframes are rendered to Markdown. */ @@ -7260,6 +7281,13 @@ export interface BrandWebScrapeSitemapParams { */ domain: string; + /** + * Optional outbound HTTP headers forwarded only to the target URL, sent as + * deep-object query params such as headers[X-Custom]=value. When provided, caching + * is bypassed: the result is neither read from nor written to cache. + */ + headers?: { [key: string]: string }; + /** * Maximum number of links to return from the sitemap crawl. Defaults to 10,000. * Minimum is 1, maximum is 100,000. diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 3a2976db..aca490f8 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -317,6 +317,7 @@ describe('resource brand', () => { test.skip('webScrapeHTML: required and optional params', async () => { const response = await client.brand.webScrapeHTML({ url: 'https://example.com', + headers: { foo: 'J!' }, includeFrames: true, maxAgeMs: 0, pdf: { @@ -351,6 +352,7 @@ describe('resource brand', () => { maxTimePerMs: 1, resolution: true, }, + headers: { foo: 'J!' }, maxAgeMs: 0, timeoutMS: 1000, waitForMs: 0, @@ -373,6 +375,7 @@ describe('resource brand', () => { test.skip('webScrapeMd: required and optional params', async () => { const response = await client.brand.webScrapeMd({ url: 'https://example.com', + headers: { foo: 'J!' }, includeFrames: true, includeImages: true, includeLinks: true, @@ -405,6 +408,7 @@ describe('resource brand', () => { test.skip('webScrapeSitemap: required and optional params', async () => { const response = await client.brand.webScrapeSitemap({ domain: 'domain', + headers: { foo: 'J!' }, maxLinks: 1, timeoutMS: 1000, urlRegex: '^https?://[^/]+/blog/', From 199184ff04a85e62055935e9d20c76d5738c92fd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:16:33 +0000 Subject: [PATCH 084/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a162a040..747631f5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-6ed467d40802bbe92c036743ad980f3cb986626e18a8e3b743e05382eee00b97.yml -openapi_spec_hash: 5fb10c717fc138f1202f8395b37713db +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-481daa177869e994747e1970f2344d2e429788465e1993bca093510c2d8aa5a9.yml +openapi_spec_hash: 860a045bcc1420095a4a77d2b4f656e2 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 82c20a0e8dd954aba80d6122930211e3e71ee884 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 15:13:46 +0000 Subject: [PATCH 085/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 5 +++-- src/resources/brand.ts | 10 +++++++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index 747631f5..15445771 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-481daa177869e994747e1970f2344d2e429788465e1993bca093510c2d8aa5a9.yml -openapi_spec_hash: 860a045bcc1420095a4a77d2b4f656e2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-554674c982facf89dfb61a919d7585a1c6a18c8253a58f67f9c6d77f1defa669.yml +openapi_spec_hash: 2520368979ea4359e5d6d47de1d15eda config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index f331763c..50783a0c 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -600,9 +600,10 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', 'waitForMs?: number;', ], - response: '{ html: string; success: true; url: string; }', + response: + "{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }", markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, headers?: object, includeFrames?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, waitForMs?: number): { html: string; success: true; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; url: string; }`\n\n - `html: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, headers?: object, includeFrames?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, waitForMs?: number): { html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n - `html: string`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index dae0bf11..7cee1f44 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -5134,7 +5134,9 @@ export namespace BrandRetrieveSimplifiedResponse { export interface BrandWebScrapeHTMLResponse { /** - * Raw HTML content of the page + * The scraped content of the page. For normal pages this is the raw HTML. When the + * page is a sitemap or feed served behind an XSL stylesheet (which browsers render + * into HTML), this is the underlying XML instead — see the `type` field. */ html: string; @@ -5143,6 +5145,12 @@ export interface BrandWebScrapeHTMLResponse { */ success: true; + /** + * Detected content type of the returned `html` field. Sitemaps and feeds are + * surfaced as `xml`; ordinary pages are `html`. + */ + type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; + /** * The URL that was scraped */ From fa6f1800704693777e7b29ccb33a6fdd3afac80c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 22:03:53 +0000 Subject: [PATCH 086/100] feat(api): api update --- .stats.yml | 4 +-- packages/mcp-server/src/local-docs-search.ts | 8 ++++-- src/resources/brand.ts | 28 ++++++++++++++++++++ tests/api-resources/brand.test.ts | 4 +++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 15445771..74edb1aa 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-554674c982facf89dfb61a919d7585a1c6a18c8253a58f67f9c6d77f1defa669.yml -openapi_spec_hash: 2520368979ea4359e5d6d47de1d15eda +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-43306d74a09e6e1f57977311aaf406e54538a4dc5a4c4ee544fa2f0deef85ab2.yml +openapi_spec_hash: 2a58ccda9d329901cac7d782ad49c848 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 50783a0c..9eb3ce02 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -593,8 +593,10 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.webScrapeHTML', params: [ 'url: string;', + 'excludeSelectors?: string[];', 'headers?: object;', 'includeFrames?: boolean;', + 'includeSelectors?: string[];', 'maxAgeMs?: number;', 'pdf?: { end?: number; shouldParse?: boolean; start?: number; };', 'timeoutMS?: number;', @@ -603,7 +605,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }", markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, headers?: object, includeFrames?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, waitForMs?: number): { html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n - `html: string`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, waitForMs?: number): { html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n - `html: string`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', @@ -641,10 +643,12 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.webScrapeMd', params: [ 'url: string;', + 'excludeSelectors?: string[];', 'headers?: object;', 'includeFrames?: boolean;', 'includeImages?: boolean;', 'includeLinks?: boolean;', + 'includeSelectors?: string[];', 'maxAgeMs?: number;', 'pdf?: { end?: number; shouldParse?: boolean; start?: number; };', 'shortenBase64Images?: boolean;', @@ -654,7 +658,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ ], response: '{ markdown: string; success: true; url: string; }', markdown: - "## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, headers?: object, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + '## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove before conversion to Markdown. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching HTML subtrees (and their descendants) are kept before conversion 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from \'brand.dev\';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: \'https://example.com\' });\n\nconsole.log(response);\n```', perLanguage: { typescript: { method: 'client.brand.webScrapeMd', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 7cee1f44..d82e8e06 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -7059,6 +7059,13 @@ export interface BrandWebScrapeHTMLParams { */ url: string; + /** + * CSS selectors to remove from the result. Applied after includeSelectors. + * Exclusion takes precedence: an element matching both is removed. Examples: + * "nav", "footer", ".ad-banner", "[aria-hidden=true]". + */ + excludeSelectors?: Array; + /** * Optional outbound HTTP headers forwarded only to the target URL, sent as * deep-object query params such as headers[X-Custom]=value. When provided, caching @@ -7071,6 +7078,13 @@ export interface BrandWebScrapeHTMLParams { */ includeFrames?: boolean; + /** + * CSS selectors. When provided, only matching subtrees (and their descendants) are + * kept and everything else is dropped. When omitted, the entire document is kept. + * Examples: "article.main", "#content", "[role=main]". + */ + includeSelectors?: Array; + /** * 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 @@ -7198,6 +7212,13 @@ export interface BrandWebScrapeMdParams { */ url: string; + /** + * CSS selectors to remove before conversion to Markdown. Applied after + * includeSelectors. Exclusion takes precedence: an element matching both is + * removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]". + */ + excludeSelectors?: Array; + /** * Optional outbound HTTP headers forwarded only to the target URL, sent as * deep-object query params such as headers[X-Custom]=value. When provided, caching @@ -7220,6 +7241,13 @@ export interface BrandWebScrapeMdParams { */ includeLinks?: boolean; + /** + * CSS selectors. When provided, only matching HTML subtrees (and their + * descendants) are kept before conversion to Markdown. When omitted, the entire + * document is kept. Examples: "article.main", "#content", "[role=main]". + */ + includeSelectors?: Array; + /** * 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 diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index aca490f8..8a309026 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -317,8 +317,10 @@ describe('resource brand', () => { test.skip('webScrapeHTML: required and optional params', async () => { const response = await client.brand.webScrapeHTML({ url: 'https://example.com', + excludeSelectors: ['string'], headers: { foo: 'J!' }, includeFrames: true, + includeSelectors: ['string'], maxAgeMs: 0, pdf: { end: 1, @@ -375,10 +377,12 @@ describe('resource brand', () => { test.skip('webScrapeMd: required and optional params', async () => { const response = await client.brand.webScrapeMd({ url: 'https://example.com', + excludeSelectors: ['string'], headers: { foo: 'J!' }, includeFrames: true, includeImages: true, includeLinks: true, + includeSelectors: ['string'], maxAgeMs: 0, pdf: { end: 1, From 70ca89f0de96b7b7f5ff4e0d29d2134549814ecc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 20:10:19 +0000 Subject: [PATCH 087/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 74edb1aa..f2df7282 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-43306d74a09e6e1f57977311aaf406e54538a4dc5a4c4ee544fa2f0deef85ab2.yml -openapi_spec_hash: 2a58ccda9d329901cac7d782ad49c848 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-d4cdc8c2c8bb0012c2368aeae40ed20f3c93ea68dcd9892db18aa1e06642203d.yml +openapi_spec_hash: e71b8ca8fa8041c8628f82afed471199 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From ad88d7c77769ee391afd53d7c19763d2af22f847 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 21:01:33 +0000 Subject: [PATCH 088/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 3 ++- src/resources/brand.ts | 6 ++++++ tests/api-resources/brand.test.ts | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index f2df7282..db86bba3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-d4cdc8c2c8bb0012c2368aeae40ed20f3c93ea68dcd9892db18aa1e06642203d.yml -openapi_spec_hash: e71b8ca8fa8041c8628f82afed471199 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-661aa162bbdbb94bfa2a225feb7be095dec450591814eda5d5f7cbd10e0d131d.yml +openapi_spec_hash: 3dc831d586372da3b88e4636213de7f0 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 9eb3ce02..25e94eda 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -600,12 +600,13 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'maxAgeMs?: number;', 'pdf?: { end?: number; shouldParse?: boolean; start?: number; };', 'timeoutMS?: number;', + 'useMainContentOnly?: boolean;', 'waitForMs?: number;', ], response: "{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }", markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, waitForMs?: number): { html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n - `html: string`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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- `useMainContentOnly?: boolean`\n When true, return only the page's main content in the HTML response, excluding headers, footers, sidebars, and navigation when detectable.\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n - `html: string`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index d82e8e06..4c1fc6c6 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -7105,6 +7105,12 @@ export interface BrandWebScrapeHTMLParams { */ timeoutMS?: number; + /** + * When true, return only the page's main content in the HTML response, excluding + * headers, footers, sidebars, and navigation when detectable. + */ + useMainContentOnly?: boolean; + /** * Optional browser wait time in milliseconds after initial page load. Min: 0. Max: * 30000 (30 seconds). diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index 8a309026..b4a4cc3a 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -328,6 +328,7 @@ describe('resource brand', () => { start: 1, }, timeoutMS: 1000, + useMainContentOnly: true, waitForMs: 0, }); }); From 97ccc8374c7564e50cda63f6b4d881967991c0ee Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 21:48:09 +0000 Subject: [PATCH 089/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index db86bba3..5dbaf4e0 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-661aa162bbdbb94bfa2a225feb7be095dec450591814eda5d5f7cbd10e0d131d.yml -openapi_spec_hash: 3dc831d586372da3b88e4636213de7f0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-437213902ba1307c7c8733d00945a188a7aa6af9e5c1f7fa1a8ffcc0f692efc8.yml +openapi_spec_hash: 0141ce3e02c643164e5a09eb2f2e89b4 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 165f3c78528b8e161a8913482a2fc11e14a925e5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 01:10:57 +0000 Subject: [PATCH 090/100] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 69 ++-- src/resources/brand.ts | 360 +++++++++++++++++++ 3 files changed, 398 insertions(+), 35 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5dbaf4e0..503623ef 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-437213902ba1307c7c8733d00945a188a7aa6af9e5c1f7fa1a8ffcc0f692efc8.yml -openapi_spec_hash: 0141ce3e02c643164e5a09eb2f2e89b4 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-5545bb30aeac61ddb7d2b84ada399e9cd1cdc531a494b41e2ccf720056bdd437.yml +openapi_spec_hash: 554a88e7acd677dd0acac34b3900e5c6 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 25e94eda..9f3539de 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -66,9 +66,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }", markdown: - "## retrieve\n\n`client.brand.retrieve(domain: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve`\n\nRetrieve logos, backdrops, colors, industry, description, and more from any domain\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve brand data for (e.g., 'example.com', 'google.com'). Cannot be used with name or ticker parameters.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data. Works with all three lookup methods.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst brand = await client.brand.retrieve({ domain: 'domain' });\n\nconsole.log(brand);\n```", + "## retrieve\n\n`client.brand.retrieve(domain: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; key_metadata?: object; status?: string; }`\n\n**get** `/brand/retrieve`\n\nRetrieve logos, backdrops, colors, industry, description, and more from any domain\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve brand data for (e.g., 'example.com', 'google.com'). Cannot be used with name or ticker parameters.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data. Works with all three lookup methods.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst brand = await client.brand.retrieve({ domain: 'domain' });\n\nconsole.log(brand);\n```", perLanguage: { typescript: { method: 'client.brand.retrieve', @@ -113,9 +113,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }", markdown: - "## retrieve_by_ticker\n\n`client.brand.retrieveByTicker(ticker: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, ticker_exchange?: string, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-ticker`\n\nRetrieve brand information using a stock ticker symbol.\n\n### Parameters\n\n- `ticker: string`\n Stock ticker symbol to retrieve brand data for (e.g., 'AAPL', 'GOOGL', 'BRK.A'). Must be 1-15 characters, letters/numbers/dots only.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `ticker_exchange?: string`\n Optional stock exchange for the ticker. Defaults to NASDAQ if not specified.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response);\n```", + "## retrieve_by_ticker\n\n`client.brand.retrieveByTicker(ticker: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, ticker_exchange?: string, timeoutMS?: number): { brand?: object; code?: number; key_metadata?: object; status?: string; }`\n\n**get** `/brand/retrieve-by-ticker`\n\nRetrieve brand information using a stock ticker symbol.\n\n### Parameters\n\n- `ticker: string`\n Stock ticker symbol to retrieve brand data for (e.g., 'AAPL', 'GOOGL', 'BRK.A'). Must be 1-15 characters, letters/numbers/dots only.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `ticker_exchange?: string`\n Optional stock exchange for the ticker. Defaults to NASDAQ if not specified.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByTicker({ ticker: 'ticker' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveByTicker', @@ -160,9 +160,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }", markdown: - "## retrieve_by_isin\n\n`client.brand.retrieveByIsin(isin: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-isin`\n\nRetrieve brand information using an ISIN (International Securities Identification Number). \n\n### Parameters\n\n- `isin: string`\n ISIN (International Securities Identification Number) to retrieve brand data for (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters followed by 9 alphanumeric characters and ending with a digit.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response);\n```", + "## retrieve_by_isin\n\n`client.brand.retrieveByIsin(isin: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; key_metadata?: object; status?: string; }`\n\n**get** `/brand/retrieve-by-isin`\n\nRetrieve brand information using an ISIN (International Securities Identification Number). \n\n### Parameters\n\n- `isin: string`\n ISIN (International Securities Identification Number) to retrieve brand data for (e.g., 'AU000000IMD5', 'US0378331005'). Must be exactly 12 characters: 2 letters followed by 9 alphanumeric characters and ending with a digit.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByIsin({ isin: 'SE60513A9993' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveByIsin', @@ -207,9 +207,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }", markdown: - "## retrieve_by_name\n\n`client.brand.retrieveByName(name: string, country_gl?: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-name`\n\nRetrieve brand information using a company name.\n\n### Parameters\n\n- `name: string`\n Company name to retrieve brand data for (e.g., 'Apple Inc', 'Microsoft Corporation'). Must be 3-30 characters.\n\n- `country_gl?: string`\n Optional country code hint (GL parameter) to specify the country for the company name.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response);\n```", + "## retrieve_by_name\n\n`client.brand.retrieveByName(name: string, country_gl?: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; key_metadata?: object; status?: string; }`\n\n**get** `/brand/retrieve-by-name`\n\nRetrieve brand information using a company name.\n\n### Parameters\n\n- `name: string`\n Company name to retrieve brand data for (e.g., 'Apple Inc', 'Microsoft Corporation'). Must be 3-30 characters.\n\n- `country_gl?: string`\n Optional country code hint (GL parameter) to specify the country for the company name.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByName({ name: 'xxx' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveByName', @@ -254,9 +254,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }", markdown: - "## retrieve_by_email\n\n`client.brand.retrieveByEmail(email: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-by-email`\n\nRetrieve brand information using an email address while detecting disposable and free email addresses. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.\n\n### Parameters\n\n- `email: string`\n Email address to retrieve brand data for (e.g., 'contact@example.com'). The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", + "## retrieve_by_email\n\n`client.brand.retrieveByEmail(email: string, force_language?: string, maxAgeMs?: number, maxSpeed?: boolean, timeoutMS?: number): { brand?: object; code?: number; key_metadata?: object; status?: string; }`\n\n**get** `/brand/retrieve-by-email`\n\nRetrieve brand information using an email address while detecting disposable and free email addresses. Disposable and free email addresses (like gmail.com, yahoo.com) will throw a 422 error.\n\n### Parameters\n\n- `email: string`\n Email address to retrieve brand data for (e.g., 'contact@example.com'). The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveByEmail', @@ -305,9 +305,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }", + "{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }", markdown: - "## identify_from_transaction\n\n`client.brand.identifyFromTransaction(transaction_info: string, city?: string, country_gl?: string, force_language?: string, high_confidence_only?: boolean, maxSpeed?: boolean, mcc?: string, phone?: number, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/transaction_identifier`\n\nEndpoint specially designed for platforms that want to identify transaction data by the transaction title.\n\n### Parameters\n\n- `transaction_info: string`\n Transaction information to identify the brand\n\n- `city?: string`\n Optional city name to prioritize when searching for the brand.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `high_confidence_only?: boolean`\n When set to true, the API will perform an additional verification steps to ensure the identified brand matches the transaction with high confidence.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `mcc?: string`\n Optional Merchant Category Code (MCC) to help identify the business category/industry. \n\n- `phone?: number`\n Optional phone number from the transaction to help verify brand match.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.identifyFromTransaction({ transaction_info: 'transaction_info' });\n\nconsole.log(response);\n```", + "## identify_from_transaction\n\n`client.brand.identifyFromTransaction(transaction_info: string, city?: string, country_gl?: string, force_language?: string, high_confidence_only?: boolean, maxSpeed?: boolean, mcc?: string, phone?: number, timeoutMS?: number): { brand?: object; code?: number; key_metadata?: object; status?: string; }`\n\n**get** `/brand/transaction_identifier`\n\nEndpoint specially designed for platforms that want to identify transaction data by the transaction title.\n\n### Parameters\n\n- `transaction_info: string`\n Transaction information to identify the brand\n\n- `city?: string`\n Optional city name to prioritize when searching for the brand.\n\n- `country_gl?: string`\n Optional country code (GL parameter) to specify the country. This affects the geographic location used for search queries.\n\n- `force_language?: string`\n Optional parameter to force the language of the retrieved brand data.\n\n- `high_confidence_only?: boolean`\n When set to true, the API will perform an additional verification steps to ensure the identified brand matches the transaction with high confidence.\n\n- `maxSpeed?: boolean`\n Optional parameter to optimize the API call for maximum speed. When set to true, the API will skip time-consuming operations for faster response at the cost of less comprehensive data.\n\n- `mcc?: string`\n Optional Merchant Category Code (MCC) to help identify the business category/industry. \n\n- `phone?: number`\n Optional phone number from the transaction to help verify brand match.\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- `{ brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: object[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }`\n\n - `brand?: { address?: { city?: string; country?: string; country_code?: string; postal_code?: string; state_code?: string; state_province?: string; street?: string; }; backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; description?: string; domain?: string; email?: string; industries?: { eic?: { industry: string; subindustry: string; }[]; }; is_nsfw?: boolean; links?: { blog?: string; careers?: string; contact?: string; pricing?: string; privacy?: string; terms?: string; }; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; phone?: string; primary_language?: string; slogan?: string; socials?: { type?: string; url?: string; }[]; stock?: { exchange?: string; ticker?: string; }; title?: string; }`\n - `code?: number`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.identifyFromTransaction({ transaction_info: 'transaction_info' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.identifyFromTransaction', @@ -351,9 +351,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'timeoutMS?: number;', ], response: - '{ data_extracted?: { datapoint_name?: string; datapoint_value?: string | number | boolean | string[] | number[] | object[]; }[]; domain?: string; status?: string; urls_analyzed?: string[]; }', + '{ data_extracted?: { datapoint_name?: string; datapoint_value?: string | number | boolean | string[] | number[] | object[]; }[]; domain?: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; urls_analyzed?: string[]; }', markdown: - "## ai_query\n\n`client.brand.aiQuery(data_to_extract: { datapoint_description: string; datapoint_example: string; datapoint_name: string; datapoint_type: 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url'; datapoint_list_type?: 'string' | 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url' | 'object'; datapoint_object_schema?: object; }[], domain: string, specific_pages?: { about_us?: boolean; blog?: boolean; careers?: boolean; contact_us?: boolean; faq?: boolean; home_page?: boolean; pricing?: boolean; privacy_policy?: boolean; terms_and_conditions?: boolean; }, timeoutMS?: number): { data_extracted?: object[]; domain?: string; status?: string; urls_analyzed?: string[]; }`\n\n**post** `/brand/ai/query`\n\nUse AI to extract specific data points from a brand's website. The AI will crawl the website and extract the requested information based on the provided data points.\n\n### Parameters\n\n- `data_to_extract: { datapoint_description: string; datapoint_example: string; datapoint_name: string; datapoint_type: 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url'; datapoint_list_type?: 'string' | 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url' | 'object'; datapoint_object_schema?: object; }[]`\n Array of data points to extract from the website\n\n- `domain: string`\n The domain name to analyze\n\n- `specific_pages?: { about_us?: boolean; blog?: boolean; careers?: boolean; contact_us?: boolean; faq?: boolean; home_page?: boolean; pricing?: boolean; privacy_policy?: boolean; terms_and_conditions?: boolean; }`\n Optional object specifying which pages to analyze\n - `about_us?: boolean`\n Whether to analyze the about us page\n - `blog?: boolean`\n Whether to analyze the blog\n - `careers?: boolean`\n Whether to analyze the careers page\n - `contact_us?: boolean`\n Whether to analyze the contact us page\n - `faq?: boolean`\n Whether to analyze the FAQ page\n - `home_page?: boolean`\n Whether to analyze the home page\n - `pricing?: boolean`\n Whether to analyze the pricing page\n - `privacy_policy?: boolean`\n Whether to analyze the privacy policy page\n - `terms_and_conditions?: boolean`\n Whether to analyze the terms and conditions page\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- `{ data_extracted?: { datapoint_name?: string; datapoint_value?: string | number | boolean | string[] | number[] | object[]; }[]; domain?: string; status?: string; urls_analyzed?: string[]; }`\n\n - `data_extracted?: { datapoint_name?: string; datapoint_value?: string | number | boolean | string[] | number[] | object[]; }[]`\n - `domain?: string`\n - `status?: string`\n - `urls_analyzed?: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiQuery({ data_to_extract: [{\n datapoint_description: 'datapoint_description',\n datapoint_example: 'datapoint_example',\n datapoint_name: 'datapoint_name',\n datapoint_type: 'text',\n}], domain: 'domain' });\n\nconsole.log(response);\n```", + "## ai_query\n\n`client.brand.aiQuery(data_to_extract: { datapoint_description: string; datapoint_example: string; datapoint_name: string; datapoint_type: 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url'; datapoint_list_type?: 'string' | 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url' | 'object'; datapoint_object_schema?: object; }[], domain: string, specific_pages?: { about_us?: boolean; blog?: boolean; careers?: boolean; contact_us?: boolean; faq?: boolean; home_page?: boolean; pricing?: boolean; privacy_policy?: boolean; terms_and_conditions?: boolean; }, timeoutMS?: number): { data_extracted?: object[]; domain?: string; key_metadata?: object; status?: string; urls_analyzed?: string[]; }`\n\n**post** `/brand/ai/query`\n\nUse AI to extract specific data points from a brand's website. The AI will crawl the website and extract the requested information based on the provided data points.\n\n### Parameters\n\n- `data_to_extract: { datapoint_description: string; datapoint_example: string; datapoint_name: string; datapoint_type: 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url'; datapoint_list_type?: 'string' | 'text' | 'number' | 'date' | 'boolean' | 'list' | 'url' | 'object'; datapoint_object_schema?: object; }[]`\n Array of data points to extract from the website\n\n- `domain: string`\n The domain name to analyze\n\n- `specific_pages?: { about_us?: boolean; blog?: boolean; careers?: boolean; contact_us?: boolean; faq?: boolean; home_page?: boolean; pricing?: boolean; privacy_policy?: boolean; terms_and_conditions?: boolean; }`\n Optional object specifying which pages to analyze\n - `about_us?: boolean`\n Whether to analyze the about us page\n - `blog?: boolean`\n Whether to analyze the blog\n - `careers?: boolean`\n Whether to analyze the careers page\n - `contact_us?: boolean`\n Whether to analyze the contact us page\n - `faq?: boolean`\n Whether to analyze the FAQ page\n - `home_page?: boolean`\n Whether to analyze the home page\n - `pricing?: boolean`\n Whether to analyze the pricing page\n - `privacy_policy?: boolean`\n Whether to analyze the privacy policy page\n - `terms_and_conditions?: boolean`\n Whether to analyze the terms and conditions page\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- `{ data_extracted?: { datapoint_name?: string; datapoint_value?: string | number | boolean | string[] | number[] | object[]; }[]; domain?: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; urls_analyzed?: string[]; }`\n\n - `data_extracted?: { datapoint_name?: string; datapoint_value?: string | number | boolean | string[] | number[] | object[]; }[]`\n - `domain?: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `status?: string`\n - `urls_analyzed?: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiQuery({ data_to_extract: [{\n datapoint_description: 'datapoint_description',\n datapoint_example: 'datapoint_example',\n datapoint_name: 'datapoint_name',\n datapoint_type: 'text',\n}], domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.aiQuery', @@ -390,9 +390,10 @@ const EMBEDDED_METHODS: MethodEntry[] = [ stainlessPath: '(resource) brand > (method) prefetch', qualified: 'client.brand.prefetch', params: ['domain: string;', 'timeoutMS?: number;'], - response: '{ domain?: string; message?: string; status?: string; }', + response: + '{ domain?: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; message?: string; status?: string; }', markdown: - "## prefetch\n\n`client.brand.prefetch(domain: string, timeoutMS?: number): { domain?: string; message?: string; status?: string; }`\n\n**post** `/brand/prefetch`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency.\n\n### Parameters\n\n- `domain: string`\n Domain name to prefetch brand data for\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- `{ domain?: string; message?: string; status?: string; }`\n\n - `domain?: string`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetch({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## prefetch\n\n`client.brand.prefetch(domain: string, timeoutMS?: number): { domain?: string; key_metadata?: object; message?: string; status?: string; }`\n\n**post** `/brand/prefetch`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency.\n\n### Parameters\n\n- `domain: string`\n Domain name to prefetch brand data for\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- `{ domain?: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; message?: string; status?: string; }`\n\n - `domain?: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetch({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.prefetch', @@ -430,9 +431,10 @@ const EMBEDDED_METHODS: MethodEntry[] = [ stainlessPath: '(resource) brand > (method) prefetch_by_email', qualified: 'client.brand.prefetchByEmail', params: ['email: string;', 'timeoutMS?: number;'], - response: '{ domain?: string; message?: string; status?: string; }', + response: + '{ domain?: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; message?: string; status?: string; }', markdown: - "## prefetch_by_email\n\n`client.brand.prefetchByEmail(email: string, timeoutMS?: number): { domain?: string; message?: string; status?: string; }`\n\n**post** `/brand/prefetch-by-email`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency. This endpoint accepts an email address, extracts the domain from it, validates that it's not a disposable or free email provider, and queues the domain for prefetching.\n\n### Parameters\n\n- `email: string`\n Email address to prefetch brand data for. The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\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- `{ domain?: string; message?: string; status?: string; }`\n\n - `domain?: string`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetchByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", + "## prefetch_by_email\n\n`client.brand.prefetchByEmail(email: string, timeoutMS?: number): { domain?: string; key_metadata?: object; message?: string; status?: string; }`\n\n**post** `/brand/prefetch-by-email`\n\nSignal that you may fetch brand data for a particular domain soon to improve latency. This endpoint accepts an email address, extracts the domain from it, validates that it's not a disposable or free email provider, and queues the domain for prefetching.\n\n### Parameters\n\n- `email: string`\n Email address to prefetch brand data for. The domain will be extracted from the email. Free email providers (gmail.com, yahoo.com, etc.) and disposable email addresses are not allowed.\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- `{ domain?: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; message?: string; status?: string; }`\n\n - `domain?: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `message?: string`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.prefetchByEmail({ email: 'dev@stainless.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.prefetchByEmail', @@ -471,9 +473,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.retrieveSimplified', params: ['domain: string;', 'maxAgeMs?: number;', 'timeoutMS?: number;'], response: - "{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; status?: string; }", + "{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }", markdown: - "## retrieve_simplified\n\n`client.brand.retrieveSimplified(domain: string, maxAgeMs?: number, timeoutMS?: number): { brand?: object; code?: number; status?: string; }`\n\n**get** `/brand/retrieve-simplified`\n\nReturns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. Optimized for faster responses and reduced data transfer.\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve simplified brand data for\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\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- `{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; status?: string; }`\n\n - `brand?: { backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }`\n - `code?: number`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveSimplified({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## retrieve_simplified\n\n`client.brand.retrieveSimplified(domain: string, maxAgeMs?: number, timeoutMS?: number): { brand?: object; code?: number; key_metadata?: object; status?: string; }`\n\n**get** `/brand/retrieve-simplified`\n\nReturns a simplified version of brand data containing only essential information: domain, title, colors, logos, and backdrops. Optimized for faster responses and reduced data transfer.\n\n### Parameters\n\n- `domain: string`\n Domain name to retrieve simplified brand data for\n\n- `maxAgeMs?: number`\n Maximum age in milliseconds for cached brand data before the API performs a hard refresh. Defaults to 3 months (7776000000 ms). Values below 1 day (86400000 ms) are clamped to 1 day; values above 1 year (31536000000 ms) are clamped to 1 year.\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- `{ brand?: { backdrops?: { colors?: object[]; resolution?: object; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: object[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: object; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }; code?: number; key_metadata?: { credits_consumed: number; credits_remaining: number; }; status?: string; }`\n\n - `brand?: { backdrops?: { colors?: { hex?: string; name?: string; }[]; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; url?: string; }[]; colors?: { hex?: string; name?: string; }[]; domain?: string; logos?: { colors?: { hex?: string; name?: string; }[]; mode?: 'light' | 'dark' | 'has_opaque_background'; resolution?: { aspect_ratio?: number; height?: number; width?: number; }; type?: 'icon' | 'logo'; url?: string; }[]; title?: string; }`\n - `code?: number`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n - `status?: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.retrieveSimplified({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.retrieveSimplified', @@ -514,17 +516,17 @@ const EMBEDDED_METHODS: MethodEntry[] = [ '{ domain: string; maxAgeMs?: number; maxProducts?: number; timeoutMS?: number; } | { directUrl: string; maxAgeMs?: number; maxProducts?: number; timeoutMS?: number; };', ], response: - "{ 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[]; 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; }[]; }", perLanguage: { typescript: { method: 'client.brand.aiProducts', example: - "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.aiProducts({ domain: 'domain' });\n\nconsole.log(response.products);", + "import BrandDev from 'brand.dev';\n\nconst client = new BrandDev({\n apiKey: process.env['BRAND_DEV_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.brand.aiProducts({ domain: 'domain' });\n\nconsole.log(response.key_metadata);", }, python: { method: 'brand.ai_products', example: - 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.ai_products(\n domain="domain",\n)\nprint(response.products)', + 'import os\nfrom brand.dev import BrandDev\n\nclient = BrandDev(\n api_key=os.environ.get("BRAND_DEV_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.brand.ai_products(\n domain="domain",\n)\nprint(response.key_metadata)', }, java: { method: 'brand().aiProducts', @@ -553,9 +555,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.aiProduct', params: ['url: string;', 'maxAgeMs?: number;', 'timeoutMS?: number;'], response: - "{ is_product_page?: boolean; 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[]; 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; }; }", markdown: - "## ai_product\n\n`client.brand.aiProduct(url: string, maxAgeMs?: number, timeoutMS?: number): { is_product_page?: boolean; 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- `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; 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 - `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## ai_product\n\n`client.brand.aiProduct(url: string, maxAgeMs?: number, 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- `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 BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.aiProduct({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.aiProduct', @@ -604,9 +606,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'waitForMs?: number;', ], response: - "{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }", + "{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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- `useMainContentOnly?: boolean`\n When true, return only the page's main content in the HTML response, excluding headers, footers, sidebars, and navigation when detectable.\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; }`\n\n - `html: string`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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- `useMainContentOnly?: boolean`\n When true, return only the page's main content in the HTML response, excluding headers, footers, sidebars, and navigation when detectable.\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `html: string`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', @@ -657,9 +659,10 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'useMainContentOnly?: boolean;', 'waitForMs?: number;', ], - response: '{ markdown: string; success: true; url: string; }', + response: + '{ markdown: string; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }', markdown: - '## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove before conversion to Markdown. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching HTML subtrees (and their descendants) are kept before conversion 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from \'brand.dev\';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: \'https://example.com\' });\n\nconsole.log(response);\n```', + '## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove before conversion to Markdown. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching HTML subtrees (and their descendants) are kept before conversion 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from \'brand.dev\';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: \'https://example.com\' });\n\nconsole.log(response);\n```', perLanguage: { typescript: { method: 'client.brand.webScrapeMd', @@ -705,9 +708,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'waitForMs?: number;', ], response: - "{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }", + "{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", markdown: - "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, headers?: object, maxAgeMs?: number, timeoutMS?: number, waitForMs?: number): { images: object[]; success: true; url: string; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit. When enrichment is enabled, the entire call costs 5 credits.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\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 before collecting images. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_images\n\n`client.brand.webScrapeImages(url: string, enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }, headers?: object, maxAgeMs?: number, timeoutMS?: number, waitForMs?: number): { images: object[]; success: true; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/images`\n\nExtract image assets from a web page, including standard URLs, inline SVGs, data URIs, responsive image sources, metadata, CSS backgrounds, video posters, and embeds. The base request costs 1 credit. When enrichment is enabled, the entire call costs 5 credits.\n\n### Parameters\n\n- `url: string`\n Page URL to inspect. Must include http:// or https://.\n\n- `enrichment?: { classification?: boolean; hostedUrl?: boolean; maxTimePerMs?: number; resolution?: boolean; }`\n Optional per-image processing, sent as deep-object query params such as enrichment[resolution]=true.\n - `classification?: boolean`\n Classify each image by visual asset type.\n - `hostedUrl?: boolean`\n Host materializable images on the Brand.dev CDN and return their URL and MIME type.\n - `maxTimePerMs?: number`\n Per-image enrichment timeout in milliseconds. Default: 30000. Maximum: 60000.\n - `resolution?: boolean`\n Measure image width and height when possible.\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `maxAgeMs?: number`\n Reuse a cached result this many milliseconds old or newer. Default: 86400000 (1 day). Set to 0 to bypass cache. Maximum: 2592000000 (30 days).\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 before collecting images. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `images: { alt: string; element: 'img' | 'svg' | 'link' | 'source' | 'video' | 'css' | 'object' | 'meta' | 'background'; src: string; type: 'url' | 'html' | 'base64'; enrichment?: { height?: number; mimetype?: string; type?: 'photography' | 'illustration' | 'logo' | 'wordmark' | 'icon' | 'pattern' | 'graphic' | 'other'; url?: string; width?: number; }; }[]`\n - `success: true`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeImages({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeImages', @@ -751,9 +754,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'urlRegex?: string;', ], response: - '{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }', + '{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }', markdown: - "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, headers?: object, maxLinks?: number, timeoutMS?: number, urlRegex?: string): { domain: string; meta: object; success: true; urls: string[]; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\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 Optional RE2-compatible regex pattern. Only URLs matching this pattern are returned and counted against maxLinks.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", + "## web_scrape_sitemap\n\n`client.brand.webScrapeSitemap(domain: string, headers?: object, maxLinks?: number, timeoutMS?: number, urlRegex?: string): { domain: string; meta: object; success: true; urls: string[]; key_metadata?: object; }`\n\n**get** `/web/scrape/sitemap`\n\nCrawl an entire website's sitemap and return all discovered page URLs.\n\n### Parameters\n\n- `domain: string`\n Domain to build a sitemap for\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `maxLinks?: number`\n Maximum number of links to return from the sitemap crawl. Defaults to 10,000. Minimum is 1, maximum is 100,000.\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 Optional RE2-compatible regex pattern. Only URLs matching this pattern are returned and counted against maxLinks.\n\n### Returns\n\n- `{ domain: string; meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }; success: true; urls: string[]; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `domain: string`\n - `meta: { errors: number; sitemapsDiscovered: number; sitemapsFetched: number; sitemapsSkipped: number; }`\n - `success: true`\n - `urls: string[]`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeSitemap({ domain: 'domain' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeSitemap', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 4c1fc6c6..57069cff 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -178,6 +178,12 @@ export interface BrandRetrieveResponse { */ code?: number; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandRetrieveResponse.KeyMetadata; + /** * Status of the response, e.g., 'ok' */ @@ -922,6 +928,22 @@ export namespace BrandRetrieveResponse { ticker?: string; } } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandAIProductResponse { @@ -930,6 +952,12 @@ export interface BrandAIProductResponse { */ is_product_page?: boolean; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandAIProductResponse.KeyMetadata; + /** * The detected ecommerce platform, or null if not a product page */ @@ -942,6 +970,22 @@ export interface BrandAIProductResponse { } export namespace BrandAIProductResponse { + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } + /** * The extracted product data, or null if not a product page */ @@ -1019,6 +1063,12 @@ export namespace BrandAIProductResponse { } export interface BrandAIProductsResponse { + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandAIProductsResponse.KeyMetadata; + /** * Array of products extracted from the website */ @@ -1026,6 +1076,22 @@ export interface BrandAIProductsResponse { } export namespace BrandAIProductsResponse { + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } + export interface Product { /** * Description of the product @@ -1110,6 +1176,12 @@ export interface BrandAIQueryResponse { */ domain?: string; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandAIQueryResponse.KeyMetadata; + /** * Status of the response, e.g., 'ok' */ @@ -1134,6 +1206,22 @@ export namespace BrandAIQueryResponse { */ datapoint_value?: string | number | boolean | Array | Array | Array; } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandIdentifyFromTransactionResponse { @@ -1147,6 +1235,12 @@ export interface BrandIdentifyFromTransactionResponse { */ code?: number; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandIdentifyFromTransactionResponse.KeyMetadata; + /** * Status of the response, e.g., 'ok' */ @@ -1891,6 +1985,22 @@ export namespace BrandIdentifyFromTransactionResponse { ticker?: string; } } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandPrefetchResponse { @@ -1899,6 +2009,12 @@ export interface BrandPrefetchResponse { */ domain?: string; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandPrefetchResponse.KeyMetadata; + /** * Success message */ @@ -1910,12 +2026,36 @@ export interface BrandPrefetchResponse { status?: string; } +export namespace BrandPrefetchResponse { + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } +} + export interface BrandPrefetchByEmailResponse { /** * The domain that was queued for prefetching */ domain?: string; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandPrefetchByEmailResponse.KeyMetadata; + /** * Success message */ @@ -1927,6 +2067,24 @@ export interface BrandPrefetchByEmailResponse { status?: string; } +export namespace BrandPrefetchByEmailResponse { + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } +} + export interface BrandRetrieveByEmailResponse { /** * Detailed brand information @@ -1938,6 +2096,12 @@ export interface BrandRetrieveByEmailResponse { */ code?: number; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandRetrieveByEmailResponse.KeyMetadata; + /** * Status of the response, e.g., 'ok' */ @@ -2682,6 +2846,22 @@ export namespace BrandRetrieveByEmailResponse { ticker?: string; } } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandRetrieveByIsinResponse { @@ -2695,6 +2875,12 @@ export interface BrandRetrieveByIsinResponse { */ code?: number; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandRetrieveByIsinResponse.KeyMetadata; + /** * Status of the response, e.g., 'ok' */ @@ -3439,6 +3625,22 @@ export namespace BrandRetrieveByIsinResponse { ticker?: string; } } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandRetrieveByNameResponse { @@ -3452,6 +3654,12 @@ export interface BrandRetrieveByNameResponse { */ code?: number; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandRetrieveByNameResponse.KeyMetadata; + /** * Status of the response, e.g., 'ok' */ @@ -4196,6 +4404,22 @@ export namespace BrandRetrieveByNameResponse { ticker?: string; } } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandRetrieveByTickerResponse { @@ -4209,6 +4433,12 @@ export interface BrandRetrieveByTickerResponse { */ code?: number; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandRetrieveByTickerResponse.KeyMetadata; + /** * Status of the response, e.g., 'ok' */ @@ -4953,6 +5183,22 @@ export namespace BrandRetrieveByTickerResponse { ticker?: string; } } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandRetrieveSimplifiedResponse { @@ -4966,6 +5212,12 @@ export interface BrandRetrieveSimplifiedResponse { */ code?: number; + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandRetrieveSimplifiedResponse.KeyMetadata; + /** * Status of the response, e.g., 'ok' */ @@ -5130,6 +5382,22 @@ export namespace BrandRetrieveSimplifiedResponse { } } } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandWebScrapeHTMLResponse { @@ -5155,6 +5423,30 @@ export interface BrandWebScrapeHTMLResponse { * The URL that was scraped */ url: string; + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandWebScrapeHTMLResponse.KeyMetadata; +} + +export namespace BrandWebScrapeHTMLResponse { + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandWebScrapeImagesResponse { @@ -5172,6 +5464,12 @@ export interface BrandWebScrapeImagesResponse { * Page URL that was scraped. */ url: string; + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandWebScrapeImagesResponse.KeyMetadata; } export namespace BrandWebScrapeImagesResponse { @@ -5233,6 +5531,22 @@ export namespace BrandWebScrapeImagesResponse { width?: number; } } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandWebScrapeMdResponse { @@ -5250,6 +5564,30 @@ export interface BrandWebScrapeMdResponse { * The URL that was scraped */ url: string; + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandWebScrapeMdResponse.KeyMetadata; +} + +export namespace BrandWebScrapeMdResponse { + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandWebScrapeSitemapResponse { @@ -5272,6 +5610,12 @@ export interface BrandWebScrapeSitemapResponse { * Array of discovered page URLs from the sitemap (max 500) */ urls: Array; + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + key_metadata?: BrandWebScrapeSitemapResponse.KeyMetadata; } export namespace BrandWebScrapeSitemapResponse { @@ -5299,6 +5643,22 @@ export namespace BrandWebScrapeSitemapResponse { */ sitemapsSkipped: number; } + + /** + * Metadata about the API key used for the request. Included in every response + * whenever a valid API key is provided, even when the response status is not 200. + */ + export interface KeyMetadata { + /** + * The number of credits consumed by this request. + */ + credits_consumed: number; + + /** + * The number of credits remaining for your organization after this request. + */ + credits_remaining: number; + } } export interface BrandRetrieveParams { From 4e023410581287c9bf09201325ee8d1cc50db9f7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 11:15:56 +0000 Subject: [PATCH 091/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 503623ef..1090a51e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-5545bb30aeac61ddb7d2b84ada399e9cd1cdc531a494b41e2ccf720056bdd437.yml -openapi_spec_hash: 554a88e7acd677dd0acac34b3900e5c6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-3bfe60884f1e3f19275b10d8d6d7d5ce22d7cd7aff6847eb433d8a9b77c2ecc7.yml +openapi_spec_hash: d6bd2e085a73b0a5d6ddfa20d5949094 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 38ebe8a5c46116f5a6547e0abeedb76d78708104 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 17:35:59 +0000 Subject: [PATCH 092/100] feat(api): api update --- src/client.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index 7f92b6b6..a2d50ff4 100644 --- a/src/client.ts +++ b/src/client.ts @@ -697,11 +697,19 @@ export class BrandDev { return () => controller.abort(); } - private buildBody({ options: { body, headers: rawHeaders } }: { options: FinalRequestOptions }): { + private buildBody({ options }: { options: FinalRequestOptions }): { bodyHeaders: HeadersLike; body: BodyInit | undefined; } { + const { body, headers: rawHeaders } = options; if (!body) { + // A resource method always passes a `body` key when its operation defines a + // request body, even if the caller omitted an optional body param. Keep the + // content-type for those, and only elide it for operations with no body at + // all (e.g. GET/DELETE). + if (body == null && 'body' in options) { + return this.#encoder({ body, headers: buildHeaders([rawHeaders]) }); + } return { bodyHeaders: undefined, body: undefined }; } const headers = buildHeaders([rawHeaders]); From 89fa60d283997c95867e09888a4ab4829f66d854 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 23:16:19 +0000 Subject: [PATCH 093/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1090a51e..8066585f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-3bfe60884f1e3f19275b10d8d6d7d5ce22d7cd7aff6847eb433d8a9b77c2ecc7.yml -openapi_spec_hash: d6bd2e085a73b0a5d6ddfa20d5949094 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-8fc464c01db0ca1150918b073df5e6b3dc4983268a3f2db1ee07b66a16b0a5fc.yml +openapi_spec_hash: 53f4527ee9daaed3e8da72bdda5657b5 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 417958d9aceb32ade749aa26667de6336fbe608c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 12:03:34 +0000 Subject: [PATCH 094/100] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 8 +- src/resources/brand.ts | 260 +++++++++++++++++++ 3 files changed, 266 insertions(+), 6 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8066585f..868ac280 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-8fc464c01db0ca1150918b073df5e6b3dc4983268a3f2db1ee07b66a16b0a5fc.yml -openapi_spec_hash: 53f4527ee9daaed3e8da72bdda5657b5 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-06023f50b1343cf31237929fe1dbbe0a8992e99eaf720daf333e190a483ca7ea.yml +openapi_spec_hash: 65b215730d00bd4ef3cd998df33b2de0 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 9f3539de..49eb7329 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -606,9 +606,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'waitForMs?: number;', ], response: - "{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", + "{ html: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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- `useMainContentOnly?: boolean`\n When true, return only the page's main content in the HTML response, excluding headers, footers, sidebars, and navigation when detectable.\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `html: string`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { html: string; metadata: object; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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- `useMainContentOnly?: boolean`\n When true, return only the page's main content in the HTML response, excluding headers, footers, sidebars, and navigation when detectable.\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `html: string`\n - `metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', @@ -660,9 +660,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'waitForMs?: number;', ], response: - '{ markdown: string; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }', + '{ markdown: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }', markdown: - '## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; success: true; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove before conversion to Markdown. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching HTML subtrees (and their descendants) are kept before conversion 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `markdown: string`\n - `success: true`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from \'brand.dev\';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: \'https://example.com\' });\n\nconsole.log(response);\n```', + '## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; metadata: object; success: true; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove before conversion to Markdown. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching HTML subtrees (and their descendants) are kept before conversion 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `markdown: string`\n - `metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }`\n - `success: true`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from \'brand.dev\';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: \'https://example.com\' });\n\nconsole.log(response);\n```', perLanguage: { typescript: { method: 'client.brand.webScrapeMd', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 57069cff..8e36e9d3 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -5408,6 +5408,11 @@ export interface BrandWebScrapeHTMLResponse { */ html: string; + /** + * Metadata extracted from the scraped page HTML. + */ + metadata: BrandWebScrapeHTMLResponse.Metadata; + /** * Indicates success */ @@ -5432,6 +5437,131 @@ export interface BrandWebScrapeHTMLResponse { } export namespace BrandWebScrapeHTMLResponse { + /** + * Metadata extracted from the scraped page HTML. + */ + export interface Metadata { + /** + * Final URL scraped after redirects or scraper fallback, when known. Falls back to + * sourceUrl when unavailable. + */ + finalUrl: string; + + /** + * Original URL requested by the caller. + */ + sourceUrl: string; + + /** + * Additional non-social meta tags not promoted to top-level metadata fields. + */ + additionalMeta?: { [key: string]: string | Array }; + + /** + * Resolved alternate links from link rel=alternate tags. + */ + alternates?: Array; + + /** + * Author metadata, when present. + */ + author?: string; + + /** + * Resolved canonical URL, when present. + */ + canonicalUrl?: string; + + /** + * Best description extracted from standard, Open Graph, or Twitter metadata. + */ + description?: string; + + /** + * Resolved favicon URL, when present. + */ + favicon?: string; + + /** + * Primary resolved preview image from Open Graph, Twitter, or image metadata. + */ + image?: string; + + /** + * JSON-LD structured data blocks parsed from the page. + */ + jsonLd?: Array<{ [key: string]: unknown }>; + + /** + * Keywords extracted from the page's keywords meta tag. + */ + keywords?: Array; + + /** + * Language extracted from html lang or language meta tags. + */ + language?: string; + + /** + * Modified timestamp/date from page metadata, when present. + */ + modifiedTime?: string; + + /** + * Open Graph metadata with the og: prefix removed and keys camel-cased. + */ + openGraph?: { [key: string]: string | Array }; + + /** + * Published timestamp/date from page metadata, when present. + */ + publishedTime?: string; + + /** + * Robots meta directive, when present. + */ + robots?: string; + + /** + * Site or application name from page metadata. + */ + siteName?: string; + + /** + * Best title extracted from the page. + */ + title?: string; + + /** + * Twitter card metadata with the twitter: prefix removed and keys camel-cased. + */ + twitter?: { [key: string]: string | Array }; + } + + export namespace Metadata { + export interface Alternate { + /** + * Resolved alternate URL. + */ + href: string; + + /** + * Language or locale for the alternate URL, when present. + */ + hreflang?: string; + + /** + * Alternate resource title, when present. + */ + title?: string; + + /** + * Alternate resource MIME type, when present. + */ + type?: string; + } + } + /** * Metadata about the API key used for the request. Included in every response * whenever a valid API key is provided, even when the response status is not 200. @@ -5555,6 +5685,11 @@ export interface BrandWebScrapeMdResponse { */ markdown: string; + /** + * Metadata extracted from the scraped page HTML. + */ + metadata: BrandWebScrapeMdResponse.Metadata; + /** * Indicates success */ @@ -5573,6 +5708,131 @@ export interface BrandWebScrapeMdResponse { } export namespace BrandWebScrapeMdResponse { + /** + * Metadata extracted from the scraped page HTML. + */ + export interface Metadata { + /** + * Final URL scraped after redirects or scraper fallback, when known. Falls back to + * sourceUrl when unavailable. + */ + finalUrl: string; + + /** + * Original URL requested by the caller. + */ + sourceUrl: string; + + /** + * Additional non-social meta tags not promoted to top-level metadata fields. + */ + additionalMeta?: { [key: string]: string | Array }; + + /** + * Resolved alternate links from link rel=alternate tags. + */ + alternates?: Array; + + /** + * Author metadata, when present. + */ + author?: string; + + /** + * Resolved canonical URL, when present. + */ + canonicalUrl?: string; + + /** + * Best description extracted from standard, Open Graph, or Twitter metadata. + */ + description?: string; + + /** + * Resolved favicon URL, when present. + */ + favicon?: string; + + /** + * Primary resolved preview image from Open Graph, Twitter, or image metadata. + */ + image?: string; + + /** + * JSON-LD structured data blocks parsed from the page. + */ + jsonLd?: Array<{ [key: string]: unknown }>; + + /** + * Keywords extracted from the page's keywords meta tag. + */ + keywords?: Array; + + /** + * Language extracted from html lang or language meta tags. + */ + language?: string; + + /** + * Modified timestamp/date from page metadata, when present. + */ + modifiedTime?: string; + + /** + * Open Graph metadata with the og: prefix removed and keys camel-cased. + */ + openGraph?: { [key: string]: string | Array }; + + /** + * Published timestamp/date from page metadata, when present. + */ + publishedTime?: string; + + /** + * Robots meta directive, when present. + */ + robots?: string; + + /** + * Site or application name from page metadata. + */ + siteName?: string; + + /** + * Best title extracted from the page. + */ + title?: string; + + /** + * Twitter card metadata with the twitter: prefix removed and keys camel-cased. + */ + twitter?: { [key: string]: string | Array }; + } + + export namespace Metadata { + export interface Alternate { + /** + * Resolved alternate URL. + */ + href: string; + + /** + * Language or locale for the alternate URL, when present. + */ + hreflang?: string; + + /** + * Alternate resource title, when present. + */ + title?: string; + + /** + * Alternate resource MIME type, when present. + */ + type?: string; + } + } + /** * Metadata about the API key used for the request. Included in every response * whenever a valid API key is provided, even when the response status is not 200. From f3c3f0af28d0ff1b88af60b0e8879d3bf7626dc1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 23:50:23 +0000 Subject: [PATCH 095/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 868ac280..addea7a8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-06023f50b1343cf31237929fe1dbbe0a8992e99eaf720daf333e190a483ca7ea.yml -openapi_spec_hash: 65b215730d00bd4ef3cd998df33b2de0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-2e475f1afc64a3d78fe8472156f5be342e36f15f60b55cdab0dd382ebe81375d.yml +openapi_spec_hash: 906e55f0fe3cb5dd15ca30e8dc3a36a9 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From 5f865188002228c7480593de43439121d96e601d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 14:43:23 +0000 Subject: [PATCH 096/100] feat(api): api update --- .stats.yml | 4 ++-- packages/mcp-server/src/local-docs-search.ts | 4 ++-- src/resources/brand.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.stats.yml b/.stats.yml index addea7a8..8e6b1e3c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-2e475f1afc64a3d78fe8472156f5be342e36f15f60b55cdab0dd382ebe81375d.yml -openapi_spec_hash: 906e55f0fe3cb5dd15ca30e8dc3a36a9 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-82a6478e390d1dbed9d0ae2757952ae47a377218d3e3ad3440ffa525ac39d8e7.yml +openapi_spec_hash: b1bc219822a30b09ceb38d670107f5cf config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 49eb7329..c2ebae57 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -606,9 +606,9 @@ const EMBEDDED_METHODS: MethodEntry[] = [ 'waitForMs?: number;', ], response: - "{ html: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", + "{ html: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { html: string; metadata: object; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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- `useMainContentOnly?: boolean`\n When true, return only the page's main content in the HTML response, excluding headers, footers, sidebars, and navigation when detectable.\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `html: string`\n - `metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { html: string; metadata: object; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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- `useMainContentOnly?: boolean`\n When true, return only the page's main content in the HTML response, excluding headers, footers, sidebars, and navigation when detectable.\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `html: string`\n - `metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 8e36e9d3..79cabc50 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -5422,7 +5422,7 @@ export interface BrandWebScrapeHTMLResponse { * Detected content type of the returned `html` field. Sitemaps and feeds are * surfaced as `xml`; ordinary pages are `html`. */ - type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf'; + type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'; /** * The URL that was scraped From 1fc11e853febda14f675468867c0b3cd63aba6fe Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 25 Jun 2026 08:44:02 +0000 Subject: [PATCH 097/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8e6b1e3c..77bc30a9 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-82a6478e390d1dbed9d0ae2757952ae47a377218d3e3ad3440ffa525ac39d8e7.yml -openapi_spec_hash: b1bc219822a30b09ceb38d670107f5cf +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-099ed9515b0e036a1afc6a4fb6c5a5f768a78160df084ffb6dd546eb354fb526.yml +openapi_spec_hash: 0aa5154a5822db3536a5f76583b4de1f config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From b0adb0b4e01fd5bde10ccd89b8d15f67a32a6e0e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 16:51:15 +0000 Subject: [PATCH 098/100] feat(api): api update --- .stats.yml | 4 +- packages/mcp-server/src/local-docs-search.ts | 6 +- src/resources/brand.ts | 420 +++++++++++++++++++ tests/api-resources/brand.test.ts | 2 + 4 files changed, 428 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 77bc30a9..0d2a1d26 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-099ed9515b0e036a1afc6a4fb6c5a5f768a78160df084ffb6dd546eb354fb526.yml -openapi_spec_hash: 0aa5154a5822db3536a5f76583b4de1f +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-57d4560e337cefa76438ac0eac547699c564fbef5eb54dc490b4d56bce5a95a8.yml +openapi_spec_hash: 9ebaf323dae78a3da354dd4c014fa197 config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index c2ebae57..1ebe344a 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -595,6 +595,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.webScrapeHTML', params: [ 'url: string;', + 'country?: string;', 'excludeSelectors?: string[];', 'headers?: object;', 'includeFrames?: boolean;', @@ -608,7 +609,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: "{ html: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }", markdown: - "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { html: string; metadata: object; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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- `useMainContentOnly?: boolean`\n When true, return only the page's main content in the HTML response, excluding headers, footers, sidebars, and navigation when detectable.\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `html: string`\n - `metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", + "## web_scrape_html\n\n`client.brand.webScrapeHTML(url: string, country?: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { html: string; metadata: object; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/html`\n\nScrapes the given URL and returns the raw HTML content of the page.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape (must include http:// or https:// protocol)\n\n- `country?: string`\n Two-letter ISO 3166-1 alpha-2 country code for the website request location. When provided, Context.dev fetches the target page from that country.\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove from the result. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: \"nav\", \"footer\", \".ad-banner\", \"[aria-hidden=true]\".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, iframes are rendered inline into the returned HTML.\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching subtrees (and their descendants) are kept and everything else is dropped. 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\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- `useMainContentOnly?: boolean`\n When true, return only the page's main content in the HTML response, excluding headers, footers, sidebars, and navigation when detectable.\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ html: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `html: string`\n - `metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }`\n - `success: true`\n - `type: 'html' | 'xml' | 'json' | 'text' | 'csv' | 'markdown' | 'svg' | 'pdf' | 'docx' | 'doc'`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from 'brand.dev';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeHTML({ url: 'https://example.com' });\n\nconsole.log(response);\n```", perLanguage: { typescript: { method: 'client.brand.webScrapeHTML', @@ -646,6 +647,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ qualified: 'client.brand.webScrapeMd', params: [ 'url: string;', + 'country?: string;', 'excludeSelectors?: string[];', 'headers?: object;', 'includeFrames?: boolean;', @@ -662,7 +664,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ response: '{ markdown: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }', markdown: - '## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; metadata: object; success: true; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove before conversion to Markdown. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching HTML subtrees (and their descendants) are kept before conversion 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `markdown: string`\n - `metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }`\n - `success: true`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from \'brand.dev\';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: \'https://example.com\' });\n\nconsole.log(response);\n```', + '## web_scrape_md\n\n`client.brand.webScrapeMd(url: string, country?: string, excludeSelectors?: string[], headers?: object, includeFrames?: boolean, includeImages?: boolean, includeLinks?: boolean, includeSelectors?: string[], maxAgeMs?: number, pdf?: { end?: number; shouldParse?: boolean; start?: number; }, shortenBase64Images?: boolean, timeoutMS?: number, useMainContentOnly?: boolean, waitForMs?: number): { markdown: string; metadata: object; success: true; url: string; key_metadata?: object; }`\n\n**get** `/web/scrape/markdown`\n\nScrapes the given URL into LLM usable Markdown.\n\n### Parameters\n\n- `url: string`\n Full URL to scrape into LLM usable Markdown (must include http:// or https:// protocol)\n\n- `country?: string`\n Two-letter ISO 3166-1 alpha-2 country code for the website request location. When provided, Context.dev fetches the target page from that country.\n\n- `excludeSelectors?: string[]`\n CSS selectors to remove before conversion to Markdown. Applied after includeSelectors. Exclusion takes precedence: an element matching both is removed. Examples: "nav", "footer", ".ad-banner", "[aria-hidden=true]".\n\n- `headers?: object`\n Optional outbound HTTP headers forwarded only to the target URL, sent as deep-object query params such as headers[X-Custom]=value. When provided, caching is bypassed: the result is neither read from nor written to cache.\n\n- `includeFrames?: boolean`\n When true, the contents of iframes are rendered to Markdown.\n\n- `includeImages?: boolean`\n Include image references in Markdown output\n\n- `includeLinks?: boolean`\n Preserve hyperlinks in Markdown output\n\n- `includeSelectors?: string[]`\n CSS selectors. When provided, only matching HTML subtrees (and their descendants) are kept before conversion 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- `pdf?: { end?: number; shouldParse?: boolean; start?: number; }`\n PDF parsing controls. Use start/end to limit text extraction and 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 - `shouldParse?: boolean`\n When true, PDF URLs are fetched and parsed. When false, PDF URLs are skipped and a 400 WEBSITE_ACCESS_ERROR is returned.\n - `start?: number`\n First 1-based PDF page to parse. When omitted, parsing starts at the first page.\n\n- `shortenBase64Images?: boolean`\n Shorten base64-encoded image data in the Markdown output\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- `useMainContentOnly?: boolean`\n Extract only the main content of the page, excluding headers, footers, sidebars, and navigation\n\n- `waitForMs?: number`\n Optional browser wait time in milliseconds after initial page load before converting the page to Markdown. Min: 0. Max: 30000 (30 seconds). \n\n### Returns\n\n- `{ markdown: string; metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }; success: true; url: string; key_metadata?: { credits_consumed: number; credits_remaining: number; }; }`\n\n - `markdown: string`\n - `metadata: { finalUrl: string; sourceUrl: string; additionalMeta?: object; alternates?: { href: string; hreflang?: string; title?: string; type?: string; }[]; author?: string; canonicalUrl?: string; description?: string; favicon?: string; image?: string; jsonLd?: object[]; keywords?: string[]; language?: string; modifiedTime?: string; openGraph?: object; publishedTime?: string; robots?: string; siteName?: string; title?: string; twitter?: object; }`\n - `success: true`\n - `url: string`\n - `key_metadata?: { credits_consumed: number; credits_remaining: number; }`\n\n### Example\n\n```typescript\nimport BrandDev from \'brand.dev\';\n\nconst client = new BrandDev();\n\nconst response = await client.brand.webScrapeMd({ url: \'https://example.com\' });\n\nconsole.log(response);\n```', perLanguage: { typescript: { method: 'client.brand.webScrapeMd', diff --git a/src/resources/brand.ts b/src/resources/brand.ts index 79cabc50..5ffe628c 100644 --- a/src/resources/brand.ts +++ b/src/resources/brand.ts @@ -7679,6 +7679,216 @@ export interface BrandWebScrapeHTMLParams { */ url: string; + /** + * Two-letter ISO 3166-1 alpha-2 country code for the website request location. + * When provided, Context.dev fetches the target page from that country. + */ + country?: + | 'ad' + | 'ae' + | 'af' + | 'ag' + | 'ai' + | 'al' + | 'am' + | 'ao' + | 'ar' + | 'at' + | 'au' + | 'aw' + | 'az' + | 'ba' + | 'bb' + | 'bd' + | 'be' + | 'bf' + | 'bg' + | 'bh' + | 'bi' + | 'bj' + | 'bm' + | 'bn' + | 'bo' + | 'bq' + | 'br' + | 'bs' + | 'bw' + | 'by' + | 'bz' + | 'ca' + | 'cd' + | 'cf' + | 'cg' + | 'ch' + | 'ci' + | 'cl' + | 'cm' + | 'cn' + | 'co' + | 'cr' + | 'cv' + | 'cw' + | 'cy' + | 'cz' + | 'de' + | 'dj' + | 'dk' + | 'dm' + | 'do' + | 'dz' + | 'ec' + | 'ee' + | 'eg' + | 'es' + | 'et' + | 'fi' + | 'fj' + | 'fr' + | 'ga' + | 'gb' + | 'gd' + | 'ge' + | 'gf' + | 'gg' + | 'gh' + | 'gm' + | 'gn' + | 'gp' + | 'gq' + | 'gr' + | 'gt' + | 'gu' + | 'gw' + | 'gy' + | 'hk' + | 'hn' + | 'hr' + | 'ht' + | 'hu' + | 'id' + | 'ie' + | 'il' + | 'im' + | 'in' + | 'iq' + | 'ir' + | 'is' + | 'it' + | 'je' + | 'jm' + | 'jo' + | 'jp' + | 'ke' + | 'kg' + | 'kh' + | 'kn' + | 'kr' + | 'kw' + | 'ky' + | 'kz' + | 'la' + | 'lb' + | 'lc' + | 'lk' + | 'lr' + | 'ls' + | 'lt' + | 'lu' + | 'lv' + | 'ly' + | 'ma' + | 'mc' + | 'md' + | 'me' + | 'mf' + | 'mg' + | 'mk' + | 'ml' + | 'mm' + | 'mn' + | 'mo' + | 'mq' + | 'mr' + | 'mt' + | 'mu' + | 'mv' + | 'mw' + | 'mx' + | 'my' + | 'mz' + | 'na' + | 'nc' + | 'ne' + | 'ng' + | 'ni' + | 'nl' + | 'no' + | 'np' + | 'nz' + | 'om' + | 'pa' + | 'pe' + | 'pf' + | 'pg' + | 'ph' + | 'pk' + | 'pl' + | 'pr' + | 'ps' + | 'pt' + | 'py' + | 'qa' + | 're' + | 'ro' + | 'rs' + | 'ru' + | 'rw' + | 'sa' + | 'sc' + | 'sd' + | 'se' + | 'sg' + | 'si' + | 'sk' + | 'sl' + | 'sm' + | 'sn' + | 'so' + | 'sr' + | 'ss' + | 'st' + | 'sv' + | 'sx' + | 'sy' + | 'sz' + | 'tc' + | 'td' + | 'tg' + | 'th' + | 'tj' + | 'tl' + | 'tm' + | 'tn' + | 'tr' + | 'tt' + | 'tw' + | 'tz' + | 'ua' + | 'ug' + | 'us' + | 'uy' + | 'uz' + | 'vc' + | 've' + | 'vg' + | 'vi' + | 'vn' + | 'ye' + | 'yt' + | 'za' + | 'zm' + | 'zw'; + /** * CSS selectors to remove from the result. Applied after includeSelectors. * Exclusion takes precedence: an element matching both is removed. Examples: @@ -7838,6 +8048,216 @@ export interface BrandWebScrapeMdParams { */ url: string; + /** + * Two-letter ISO 3166-1 alpha-2 country code for the website request location. + * When provided, Context.dev fetches the target page from that country. + */ + country?: + | 'ad' + | 'ae' + | 'af' + | 'ag' + | 'ai' + | 'al' + | 'am' + | 'ao' + | 'ar' + | 'at' + | 'au' + | 'aw' + | 'az' + | 'ba' + | 'bb' + | 'bd' + | 'be' + | 'bf' + | 'bg' + | 'bh' + | 'bi' + | 'bj' + | 'bm' + | 'bn' + | 'bo' + | 'bq' + | 'br' + | 'bs' + | 'bw' + | 'by' + | 'bz' + | 'ca' + | 'cd' + | 'cf' + | 'cg' + | 'ch' + | 'ci' + | 'cl' + | 'cm' + | 'cn' + | 'co' + | 'cr' + | 'cv' + | 'cw' + | 'cy' + | 'cz' + | 'de' + | 'dj' + | 'dk' + | 'dm' + | 'do' + | 'dz' + | 'ec' + | 'ee' + | 'eg' + | 'es' + | 'et' + | 'fi' + | 'fj' + | 'fr' + | 'ga' + | 'gb' + | 'gd' + | 'ge' + | 'gf' + | 'gg' + | 'gh' + | 'gm' + | 'gn' + | 'gp' + | 'gq' + | 'gr' + | 'gt' + | 'gu' + | 'gw' + | 'gy' + | 'hk' + | 'hn' + | 'hr' + | 'ht' + | 'hu' + | 'id' + | 'ie' + | 'il' + | 'im' + | 'in' + | 'iq' + | 'ir' + | 'is' + | 'it' + | 'je' + | 'jm' + | 'jo' + | 'jp' + | 'ke' + | 'kg' + | 'kh' + | 'kn' + | 'kr' + | 'kw' + | 'ky' + | 'kz' + | 'la' + | 'lb' + | 'lc' + | 'lk' + | 'lr' + | 'ls' + | 'lt' + | 'lu' + | 'lv' + | 'ly' + | 'ma' + | 'mc' + | 'md' + | 'me' + | 'mf' + | 'mg' + | 'mk' + | 'ml' + | 'mm' + | 'mn' + | 'mo' + | 'mq' + | 'mr' + | 'mt' + | 'mu' + | 'mv' + | 'mw' + | 'mx' + | 'my' + | 'mz' + | 'na' + | 'nc' + | 'ne' + | 'ng' + | 'ni' + | 'nl' + | 'no' + | 'np' + | 'nz' + | 'om' + | 'pa' + | 'pe' + | 'pf' + | 'pg' + | 'ph' + | 'pk' + | 'pl' + | 'pr' + | 'ps' + | 'pt' + | 'py' + | 'qa' + | 're' + | 'ro' + | 'rs' + | 'ru' + | 'rw' + | 'sa' + | 'sc' + | 'sd' + | 'se' + | 'sg' + | 'si' + | 'sk' + | 'sl' + | 'sm' + | 'sn' + | 'so' + | 'sr' + | 'ss' + | 'st' + | 'sv' + | 'sx' + | 'sy' + | 'sz' + | 'tc' + | 'td' + | 'tg' + | 'th' + | 'tj' + | 'tl' + | 'tm' + | 'tn' + | 'tr' + | 'tt' + | 'tw' + | 'tz' + | 'ua' + | 'ug' + | 'us' + | 'uy' + | 'uz' + | 'vc' + | 've' + | 'vg' + | 'vi' + | 'vn' + | 'ye' + | 'yt' + | 'za' + | 'zm' + | 'zw'; + /** * CSS selectors to remove before conversion to Markdown. Applied after * includeSelectors. Exclusion takes precedence: an element matching both is diff --git a/tests/api-resources/brand.test.ts b/tests/api-resources/brand.test.ts index b4a4cc3a..720c5681 100644 --- a/tests/api-resources/brand.test.ts +++ b/tests/api-resources/brand.test.ts @@ -317,6 +317,7 @@ describe('resource brand', () => { test.skip('webScrapeHTML: required and optional params', async () => { const response = await client.brand.webScrapeHTML({ url: 'https://example.com', + country: 'de', excludeSelectors: ['string'], headers: { foo: 'J!' }, includeFrames: true, @@ -378,6 +379,7 @@ describe('resource brand', () => { test.skip('webScrapeMd: required and optional params', async () => { const response = await client.brand.webScrapeMd({ url: 'https://example.com', + country: 'de', excludeSelectors: ['string'], headers: { foo: 'J!' }, includeFrames: true, From 095a70ba938190ef31b6d3ca5963bb74052c3550 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 21:22:42 +0000 Subject: [PATCH 099/100] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0d2a1d26..aa977d62 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 16 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-57d4560e337cefa76438ac0eac547699c564fbef5eb54dc490b4d56bce5a95a8.yml -openapi_spec_hash: 9ebaf323dae78a3da354dd4c014fa197 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev/brand.dev-7922f187360e46504102204eddd1352da5298c06fa4cb6e888d4a7ddfe751ba8.yml +openapi_spec_hash: 81d0db949cde987c61939b2cf473e33b config_hash: 91cf2dcefb99c39eb9cd3e98e15d6011 From f3daa59af7f2ab65e524d4a0336cf84d426eff6d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2026 21:23:55 +0000 Subject: [PATCH 100/100] release: 0.35.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 75 +++++++++++++++++++++++++++++++ package.json | 2 +- packages/mcp-server/manifest.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/server.ts | 2 +- src/version.ts | 2 +- 7 files changed, 81 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8878352c..3a39fd8c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.34.0" + ".": "0.35.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 3503337b..b5d7d003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,80 @@ # Changelog +## 0.35.0 (2026-06-26) + +Full Changelog: [v0.34.0...v0.35.0](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/compare/v0.34.0...v0.35.0) + +### Features + +* **api:** api update ([b0adb0b](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/b0adb0b4e01fd5bde10ccd89b8d15f67a32a6e0e)) +* **api:** api update ([5f86518](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/5f865188002228c7480593de43439121d96e601d)) +* **api:** api update ([417958d](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/417958d9aceb32ade749aa26667de6336fbe608c)) +* **api:** api update ([38ebe8a](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/38ebe8a5c46116f5a6547e0abeedb76d78708104)) +* **api:** api update ([165f3c7](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/165f3c78528b8e161a8913482a2fc11e14a925e5)) +* **api:** api update ([ad88d7c](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/ad88d7c77769ee391afd53d7c19763d2af22f847)) +* **api:** api update ([fa6f180](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/fa6f1800704693777e7b29ccb33a6fdd3afac80c)) +* **api:** api update ([82c20a0](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/82c20a0e8dd954aba80d6122930211e3e71ee884)) +* **api:** api update ([2e168c3](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/2e168c3fe448d14473ca3fc977f3559f8ddbfe1f)) +* **api:** api update ([b3bf84f](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/b3bf84fcb2fc398edf72f1ff5f3649eab37212ee)) +* **api:** api update ([59b5f95](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/59b5f95b896846a31c9c7852337f125ae65439e3)) +* **api:** api update ([1b700bf](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/1b700bfe47a384d90c945b5d6e02509d665dd0fb)) +* **api:** api update ([43869b8](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/43869b83724b01e5e28a1b23f179633f3760f74b)) +* **api:** api update ([3a511e1](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/3a511e140051649ac3ce35051d91e2adb4dd2765)) +* **api:** api update ([808759c](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/808759cee7444f52175b1d2a2558468454a348c6)) +* **api:** api update ([de2b2b7](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/de2b2b76d8d33d290b120327994d047156d77094)) +* **api:** api update ([13ea0d1](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/13ea0d141a1d859ec241e5b79b852d46bd633fd9)) +* **api:** api update ([9bfd247](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/9bfd24706e0432eed34a10457507498685be4160)) +* **api:** api update ([0a31d83](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/0a31d83edb235c2b212c6d4ca1491791f5f3bd4f)) +* **api:** api update ([54a32bf](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/54a32bf4e75bf1794b277eb4ce167004ad70d026)) +* **api:** api update ([a83efa1](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/a83efa13afc3f4f6b564dcba1eebf34e1308d388)) +* **api:** api update ([0617a88](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/0617a88b23443ea0bc13498ef589ee400ef432a1)) +* **api:** api update ([65b0a20](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/65b0a202fddb6cc91d6af6c3baa02ef48fd8085b)) +* **api:** api update ([3f941ed](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/3f941edf853250925cf0b5d314affb2dad20ea8f)) +* **api:** api update ([96f634a](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/96f634afd283dfdb24186d77fd89e6d7db7654e1)) +* **api:** api update ([f774c88](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/f774c883e3a05276669b94690517703447ddff9a)) +* **api:** api update ([634a8ee](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/634a8eeec0cc6cf55fa66468c4e12edadfc8c222)) +* **api:** api update ([7fae62a](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/7fae62af58b8ebc012fd23e39d09ab939b1bd309)) +* **api:** api update ([85a4fad](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/85a4faddcc76130685e7d683999dc2712ce388a9)) +* **api:** api update ([d702889](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/d7028891158c4821acd11093fc69172b9f591db3)) +* **api:** api update ([5819866](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/5819866293d5d87b22457a7d0f2412a726788e97)) +* **api:** api update ([4b26b87](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/4b26b8765fbe347c55159e6a3b98cd26c1f2a478)) +* **api:** api update ([eddea3f](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/eddea3f1a05a07b311c01ba7d63c5ea8006a6007)) +* **api:** api update ([d3ddae8](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/d3ddae876866735ed1d74b606b13e3904aaaea73)) +* **api:** api update ([fbf3885](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/fbf38850134f41f8c5c3ffb7688654ca4c01b72e)) +* **api:** api update ([9c5127f](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/9c5127f56d1a7cecd870ed28f39299ad07435f84)) +* **api:** api update ([2951a65](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/2951a65b2f64fff438a445501b8faa095023d48b)) +* **api:** api update ([5a8b6f2](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/5a8b6f230ddf475be3a1b9d2c2e05a930a1724b8)) +* support setting headers via env ([bdd9f46](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/bdd9f4689b6a90bff41264325dbead0397f92aed)) + + +### Bug Fixes + +* **mcp:** use `pure-lockfile` when building mcp server ([4e7a040](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/4e7a0408c41c57ac35ee99e820d2caf0d6c1b0ea)) +* **typescript:** upgrade tsc-multi so that it works with Node 26 ([e85a50a](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/e85a50ac5ef776a655b7cd7a1375a8ce634d1e4b)) + + +### Chores + +* avoid formatting file that gets changed during releases ([d9e9e3e](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/d9e9e3eb316825a053b4443977927b5589f47008)) +* **format:** run eslint and prettier separately ([cf9b19f](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/cf9b19f49aa1c18f6054e89f6fe0005db34b1e93)) +* **internal:** codegen related update ([1b4fdd6](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/1b4fdd639c77e493c053113dafff49b70dfec8ca)) +* **internal:** codegen related update ([54a4dc6](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/54a4dc6a834ee5801f0bcc326a0446598121d844)) +* **internal:** fix MCP server import ordering ([18990e2](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/18990e28444884c123f8cff50c7763ff5f3562cf)) +* **internal:** more robust bootstrap script ([6b1838d](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/6b1838d94014d4ff073c38392820cfb868d2ee28)) +* **internal:** show error causes in MCP servers when running in local mode ([bdc3563](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/bdc35636b0866d6daecd3be434a46989776fe53f)) +* **internal:** update docs ordering ([3084086](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/3084086cb5f62d71f1be21a5d4ef07aca2fc7523)) +* **mcp-server:** increase local docs search result count from 5 to 10 ([39503b6](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/39503b60104352275076fefa2b821ee1a7f9a2d5)) +* redact api-key headers in debug logs ([2ab340e](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/2ab340e31211d77b67bd67dd1caffa1af2aa9be5)) +* restructure docs search code ([31bd771](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/31bd7717da192b95f66d9f6c2bf0639ed2857055)) +* **tests:** remove redundant File import ([16509b7](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/16509b726541f4de5aa89d5ef40647abd84c9dde)) + + +### Documentation + +* clarify forwards compat behavior ([4d3fdb6](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/4d3fdb6229a1508075ce688f4e918e72608be993)) +* update logging docs ([a4e5d6c](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/a4e5d6c3560d675b3a1417ca2c62a236d89079f8)) +* update with proxy auth info ([c282252](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/commit/c282252b5e88076344bf878241233118211770fa)) + ## 0.34.0 (2026-04-03) Full Changelog: [v0.33.0...v0.34.0](https://github.com/context-dot-dev/deprecated-brand-typescript-sdk/compare/v0.33.0...v0.34.0) diff --git a/package.json b/package.json index 7616a769..fccf8c8a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "brand.dev", - "version": "0.34.0", + "version": "0.35.0", "description": "The official TypeScript library for the Brand Dev API", "author": "Brand Dev ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json index 3449da79..c01d1b23 100644 --- a/packages/mcp-server/manifest.json +++ b/packages/mcp-server/manifest.json @@ -1,7 +1,7 @@ { "dxt_version": "0.2", "name": "brand.dev-mcp", - "version": "0.34.0", + "version": "0.35.0", "description": "The official MCP Server for the Brand Dev API", "author": { "name": "Brand Dev", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 18cfcea4..d596e9f8 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "brand.dev-mcp", - "version": "0.34.0", + "version": "0.35.0", "description": "The official MCP Server for the Brand Dev API", "author": "Brand Dev ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index ad14b57e..6a1558a2 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: 'brand_dev_api', - version: '0.34.0', + version: '0.35.0', }, { instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }), diff --git a/src/version.ts b/src/version.ts index 48199984..3f1d4329 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.34.0'; // x-release-please-version +export const VERSION = '0.35.0'; // x-release-please-version