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 01/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index bee881e..7569808 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 02/87] 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 7569808..7c16337 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 b7981c4..09c8a1d 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 1bac96a..19aae4d 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 efd4b57..117f656 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 03/87] 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 7c16337..eb61618 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 19aae4d..8c35602 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 04/87] 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 d580392..02e18eb 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 05/87] 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 38784c0..316a981 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 06/87] 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 40ed550..069a2b4 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 2d84800..cc5fa0f 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 07/87] 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 eb61618..97c1cfd 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 09c8a1d..a951256 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 8c35602..33039ea 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 117f656..91a56a7 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 08/87] 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 b95cc96..2524f5a 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 09/87] feat(api): api update --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index e5e2a93..f6eae3c 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 10/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 97c1cfd..f82697e 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 11/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f82697e..4f2e69a 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 12/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 4f2e69a..b49f2b4 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 13/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b49f2b4..2eee2ea 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 14/87] 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 2eee2ea..9b7576d 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 a951256..75bc38b 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 33039ea..ca3f550 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 15/87] 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 9b7576d..41aba4a 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 75bc38b..a012ec8 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 ca3f550..a5bf290 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 91a56a7..42651dd 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 16/87] 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 41aba4a..4caa3eb 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 a012ec8..417e187 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 a5bf290..f440696 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 17/87] 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 4caa3eb..792fcdf 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 417e187..6cad233 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 f440696..47696a7 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 18/87] 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 792fcdf..0e03d0e 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 6cad233..e5edfc8 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 19/87] 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 0e03d0e..ec6d250 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 e5edfc8..73fa97b 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 47696a7..2bd24ba 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 20/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ec6d250..ff47fd4 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 21/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index ff47fd4..3e31f1c 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 22/87] 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 3e31f1c..c117657 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 1bdf5b0..6a32067 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 2524f5a..f0654dd 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 73fa97b..55210d5 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 c5ab8ae..909c9f5 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 59d68eb..1ba255f 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 2bd24ba..4a1c0ba 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 7031f6b..798b703 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 42651dd..3f7c2d2 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 23/87] 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 c117657..0198e38 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 6a32067..9cc9196 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 f0654dd..ffcb5e7 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 55210d5..5844e46 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 909c9f5..787ca94 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 1ba255f..43c4c91 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 4a1c0ba..280057f 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 798b703..6a3a086 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 3f7c2d2..ad38969 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 24/87] 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 0198e38..957b33f 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 9cc9196..89c0e1e 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 ffcb5e7..ac12f70 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 5844e46..e0c2c1a 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 787ca94..42cd024 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 43c4c91..2ca9053 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 280057f..56231af 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 6a3a086..97308d9 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 ad38969..cefbdbf 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 25/87] 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 957b33f..d1e595c 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 e0c2c1a..edbde18 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 56231af..787ab13 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 26/87] 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 d1e595c..f73f1bc 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 89c0e1e..e38e701 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 ac12f70..d55e8eb 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 edbde18..e948ca6 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 42cd024..ce712df 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 2ca9053..9af2345 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 787ab13..f061f5c 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 97308d9..24b951d 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 cefbdbf..a521327 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 27/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f73f1bc..57b9c33 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 28/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 57b9c33..53e55d8 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 29/87] 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 53e55d8..0a349a1 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 e948ca6..5c02d58 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 f061f5c..e7128f3 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 a521327..8cd9fb7 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 30/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 0a349a1..069181b 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 31/87] 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 5c02d58..ba4fd91 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 32/87] 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 a8b69ff..2e315f5 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 33/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 069181b..2008d73 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 34/87] 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 2008d73..2168363 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 ba4fd91..f236190 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 e7128f3..0dfb135 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 8cd9fb7..e413964 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 35/87] 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 2168363..c2c1aed 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 f236190..44895cc 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 0dfb135..c5d6d50 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 36/87] 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 c2c1aed..5d1e9ce 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 c5d6d50..ca034fa 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 37/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5d1e9ce..31233ea 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 38/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 31233ea..e319589 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 39/87] 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 e319589..9399718 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 44895cc..6183a23 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 ca034fa..381dfb1 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 40/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 9399718..f6a695d 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 41/87] 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 f6a695d..c591270 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 6183a23..63a1da9 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 381dfb1..01ebb43 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 e413964..87ee675 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 42/87] 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 63a1da9..e900267 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 43/87] 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 deae575..a8cdeb7 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 44/87] 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 9af2345..82ea7b3 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 45/87] 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 42ed9a0..0c860c4 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 41a735e..e643b3d 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 245c867..22c619e 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 53721ac..f1873ae 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 7a75640..b1b2c17 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 3ffb78a..1f53254 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 b668dfc..a050513 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 f6eae3c..18e7cbd 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 46/87] chore: avoid formatting file that gets changed during releases --- .prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierignore b/.prettierignore index 7cc13dd..36afd3b 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 47/87] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index c591270..725fb75 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 48/87] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 725fb75..a6057b7 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 49/87] 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 a6057b7..6eedefc 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 e900267..c146c29 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 01ebb43..2a1a132 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 87ee675..c76b098 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 50/87] 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 c146c29..2819f90 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 51/87] 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 2819f90..409c82d 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 52/87] 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 6eedefc..71256d4 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 409c82d..24d6108 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 82ea7b3..7f92b6b 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 0000000..3fda157 --- /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 0000000..67ae04e --- /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 0000000..e76a742 --- /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 0000000..c3a3620 --- /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 0000000..7e71387 --- /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 0000000..7c28dbb --- /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 0000000..4cd5657 --- /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 9dc06d9..0139cac 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 2a1a132..7767279 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 c76b098..0cb92a6 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 0000000..ea2c1b0 --- /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 0000000..74e4af8 --- /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 0000000..07e8e9f --- /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 77f661a..704398e 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 53/87] 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 71256d4..399384d 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 24d6108..2a04265 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 7767279..8e93966 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 0cb92a6..2003079 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 54/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 399384d..4178b18 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 55/87] 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 4178b18..3647616 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 2a04265..ef1ffee 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 8e93966..9a2130b 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 2003079..e330635 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 56/87] 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 ef1ffee..2e1964f 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 57/87] 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 bc741a9..83eb381 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 58/87] 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 3647616..7d8efa9 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 2e1964f..42548e8 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 9a2130b..b3bd7ae 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 e330635..67a21d3 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 59/87] 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 7d8efa9..dd6dd37 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 42548e8..0178093 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 b3bd7ae..ef44c37 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 67a21d3..3a2976d 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 60/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index dd6dd37..decd771 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 61/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index decd771..b047dd6 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 62/87] 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 8125850..9e9b6f0 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 27223ca..57aa767 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 0c860c4..039dbf9 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 63/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b047dd6..7381cdd 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 64/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 7381cdd..5f9bc77 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 65/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 5f9bc77..b034d58 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 66/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b034d58..1d491ca 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 67/87] 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 1a56997..96fb959 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 68/87] 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 22c619e..7616a76 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 d8cec01..18cfcea 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 c7e3769..c6b17b0 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 18e7cbd..00842e3 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 69/87] 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 1d491ca..1891309 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 0178093..de030da 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 ef44c37..242bb22 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 70/87] feat(api): api update --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 00842e3..06fc108 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 71/87] 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 c310f9b..35b052d 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 72/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1891309..a6a8eef 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 73/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a6a8eef..81725ad 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 74/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 81725ad..b9027d8 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 75/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b9027d8..12206a6 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 76/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 12206a6..049c672 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 77/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 049c672..3843818 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 78/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3843818..f805046 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 79/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index f805046..41f55e4 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 80/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 41f55e4..bc82c92 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 81/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index bc82c92..2b9672e 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 82/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2b9672e..4c45902 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 83/87] 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 4c45902..a162a04 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 de030da..f331763 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 242bb22..dae0bf1 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 3a2976d..aca490f 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 84/87] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index a162a04..747631f 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 85/87] 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 747631f..1544577 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 f331763..50783a0 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 dae0bf1..7cee1f4 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 86/87] 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 1544577..74edb1a 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 50783a0..9eb3ce0 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 7cee1f4..d82e8e0 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 aca490f..8a30902 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 0ed7ae9a41f46ee8a9ce2ca6621b387eeb69dc1f 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:04:40 +0000 Subject: [PATCH 87/87] release: 0.35.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 69 +++++++++++++++++++++++++++++++ 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, 75 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8878352..3a39fd8 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 3503337..5342c58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,74 @@ # Changelog +## 0.35.0 (2026-06-07) + +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 ([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 7616a76..fccf8c8 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 3449da7..c01d1b2 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 18cfcea..d596e9f 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 ad14b57..6a1558a 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 4819998..3f1d432 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