From 66a62318129d3422d6a80e57ce40cda031a0d3fc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 01:26:55 +0000 Subject: [PATCH 1/3] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 3c2db8b..2443510 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 15 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-10f7ae53f4fe4f2394c22788b648d9db742a178ed41a87beb39de741660e646b.yml -openapi_spec_hash: 9885c47a02677471a38f16dddbad1823 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-f6fec0ae4fa4572aefa111e660f98f6acfb6149c22cbd413bd3defad6c100478.yml +openapi_spec_hash: a82bf07982eae3814e8a60eb368e0ce5 config_hash: 6f10592c7d0c3bafefc1271472283217 From d51dcea705ad031b9010a391b7ed3a26c115beab Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 02:00:34 +0000 Subject: [PATCH 2/3] feat(api): manual updates --- .stats.yml | 4 +- lib/brand_dev.rb | 2 + lib/brand_dev/models.rb | 2 + .../models/brand_ai_product_params.rb | 34 ++ .../models/brand_ai_product_response.rb | 185 +++++++++ lib/brand_dev/resources/brand.rb | 29 ++ rbi/brand_dev/models.rbi | 2 + .../models/brand_ai_product_params.rbi | 56 +++ .../models/brand_ai_product_response.rbi | 368 ++++++++++++++++++ rbi/brand_dev/resources/brand.rbi | 20 + sig/brand_dev/models.rbs | 2 + .../models/brand_ai_product_params.rbs | 30 ++ .../models/brand_ai_product_response.rbs | 144 +++++++ sig/brand_dev/resources/brand.rbs | 6 + test/brand_dev/resources/brand_test.rb | 18 + 15 files changed, 900 insertions(+), 2 deletions(-) create mode 100644 lib/brand_dev/models/brand_ai_product_params.rb create mode 100644 lib/brand_dev/models/brand_ai_product_response.rb create mode 100644 rbi/brand_dev/models/brand_ai_product_params.rbi create mode 100644 rbi/brand_dev/models/brand_ai_product_response.rbi create mode 100644 sig/brand_dev/models/brand_ai_product_params.rbs create mode 100644 sig/brand_dev/models/brand_ai_product_response.rbs diff --git a/.stats.yml b/.stats.yml index 2443510..a831e36 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 15 +configured_endpoints: 16 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-f6fec0ae4fa4572aefa111e660f98f6acfb6149c22cbd413bd3defad6c100478.yml openapi_spec_hash: a82bf07982eae3814e8a60eb368e0ce5 -config_hash: 6f10592c7d0c3bafefc1271472283217 +config_hash: c3aaaa9794dba44d524c06591ab17894 diff --git a/lib/brand_dev.rb b/lib/brand_dev.rb index cd22a7d..1f65f4b 100644 --- a/lib/brand_dev.rb +++ b/lib/brand_dev.rb @@ -52,6 +52,8 @@ require_relative "brand_dev/internal/transport/base_client" require_relative "brand_dev/internal/transport/pooled_net_requester" require_relative "brand_dev/client" +require_relative "brand_dev/models/brand_ai_product_params" +require_relative "brand_dev/models/brand_ai_product_response" require_relative "brand_dev/models/brand_ai_products_params" require_relative "brand_dev/models/brand_ai_products_response" require_relative "brand_dev/models/brand_ai_query_params" diff --git a/lib/brand_dev/models.rb b/lib/brand_dev/models.rb index 71c391e..dd2155e 100644 --- a/lib/brand_dev/models.rb +++ b/lib/brand_dev/models.rb @@ -39,6 +39,8 @@ module BrandDev mod.define_sorbet_constant!(const) { T.type_alias { mod.to_sorbet_type } } end + BrandAIProductParams = BrandDev::Models::BrandAIProductParams + BrandAIProductsParams = BrandDev::Models::BrandAIProductsParams BrandAIQueryParams = BrandDev::Models::BrandAIQueryParams diff --git a/lib/brand_dev/models/brand_ai_product_params.rb b/lib/brand_dev/models/brand_ai_product_params.rb new file mode 100644 index 0000000..bf0806d --- /dev/null +++ b/lib/brand_dev/models/brand_ai_product_params.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module BrandDev + module Models + # @see BrandDev::Resources::Brand#ai_product + class BrandAIProductParams < BrandDev::Internal::Type::BaseModel + extend BrandDev::Internal::Type::RequestParameters::Converter + include BrandDev::Internal::Type::RequestParameters + + # @!attribute url + # The product page URL to extract product data from. + # + # @return [String] + required :url, String + + # @!attribute timeout_ms + # Optional timeout in milliseconds for the request. Maximum allowed value is + # 300000ms (5 minutes). + # + # @return [Integer, nil] + optional :timeout_ms, Integer, api_name: :timeoutMS + + # @!method initialize(url:, timeout_ms: nil, request_options: {}) + # Some parameter documentations has been truncated, see + # {BrandDev::Models::BrandAIProductParams} for more details. + # + # @param url [String] The product page URL to extract product data from. + # + # @param timeout_ms [Integer] Optional timeout in milliseconds for the request. Maximum allowed value is 30000 + # + # @param request_options [BrandDev::RequestOptions, Hash{Symbol=>Object}] + end + end +end diff --git a/lib/brand_dev/models/brand_ai_product_response.rb b/lib/brand_dev/models/brand_ai_product_response.rb new file mode 100644 index 0000000..b35730f --- /dev/null +++ b/lib/brand_dev/models/brand_ai_product_response.rb @@ -0,0 +1,185 @@ +# frozen_string_literal: true + +module BrandDev + module Models + # @see BrandDev::Resources::Brand#ai_product + class BrandAIProductResponse < BrandDev::Internal::Type::BaseModel + # @!attribute is_product_page + # Whether the given URL is a product detail page + # + # @return [Boolean, nil] + optional :is_product_page, BrandDev::Internal::Type::Boolean + + # @!attribute platform + # The detected ecommerce platform, or null if not a product page + # + # @return [Symbol, BrandDev::Models::BrandAIProductResponse::Platform, nil] + optional :platform, enum: -> { BrandDev::Models::BrandAIProductResponse::Platform }, nil?: true + + # @!attribute product + # The extracted product data, or null if not a product page + # + # @return [BrandDev::Models::BrandAIProductResponse::Product, nil] + optional :product, -> { BrandDev::Models::BrandAIProductResponse::Product }, nil?: true + + # @!method initialize(is_product_page: nil, platform: nil, product: nil) + # @param is_product_page [Boolean] Whether the given URL is a product detail page + # + # @param platform [Symbol, BrandDev::Models::BrandAIProductResponse::Platform, nil] The detected ecommerce platform, or null if not a product page + # + # @param product [BrandDev::Models::BrandAIProductResponse::Product, nil] The extracted product data, or null if not a product page + + # The detected ecommerce platform, or null if not a product page + # + # @see BrandDev::Models::BrandAIProductResponse#platform + module Platform + extend BrandDev::Internal::Type::Enum + + AMAZON = :amazon + TIKTOK_SHOP = :tiktok_shop + ETSY = :etsy + GENERIC = :generic + + # @!method self.values + # @return [Array] + end + + # @see BrandDev::Models::BrandAIProductResponse#product + class Product < BrandDev::Internal::Type::BaseModel + # @!attribute description + # Description of the product + # + # @return [String] + required :description, String + + # @!attribute features + # List of product features + # + # @return [Array] + required :features, BrandDev::Internal::Type::ArrayOf[String] + + # @!attribute name + # Name of the product + # + # @return [String] + required :name, String + + # @!attribute tags + # Tags associated with the product + # + # @return [Array] + required :tags, BrandDev::Internal::Type::ArrayOf[String] + + # @!attribute target_audience + # Target audience for the product (array of strings) + # + # @return [Array] + required :target_audience, BrandDev::Internal::Type::ArrayOf[String] + + # @!attribute billing_frequency + # Billing frequency for the product + # + # @return [Symbol, BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency, nil] + optional :billing_frequency, + enum: -> { BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency }, + nil?: true + + # @!attribute category + # Category of the product + # + # @return [String, nil] + optional :category, String, nil?: true + + # @!attribute currency + # Currency code for the price (e.g., USD, EUR) + # + # @return [String, nil] + optional :currency, String, nil?: true + + # @!attribute image_url + # URL to the product image + # + # @return [String, nil] + optional :image_url, String, nil?: true + + # @!attribute price + # Price of the product + # + # @return [Float, nil] + optional :price, Float, nil?: true + + # @!attribute pricing_model + # Pricing model for the product + # + # @return [Symbol, BrandDev::Models::BrandAIProductResponse::Product::PricingModel, nil] + optional :pricing_model, + enum: -> { BrandDev::Models::BrandAIProductResponse::Product::PricingModel }, + nil?: true + + # @!attribute url + # URL to the product page + # + # @return [String, nil] + optional :url, String, nil?: true + + # @!method initialize(description:, features:, name:, tags:, target_audience:, billing_frequency: nil, category: nil, currency: nil, image_url: nil, price: nil, pricing_model: nil, url: nil) + # The extracted product data, or null if not a product page + # + # @param description [String] Description of the product + # + # @param features [Array] List of product features + # + # @param name [String] Name of the product + # + # @param tags [Array] Tags associated with the product + # + # @param target_audience [Array] Target audience for the product (array of strings) + # + # @param billing_frequency [Symbol, BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency, nil] Billing frequency for the product + # + # @param category [String, nil] Category of the product + # + # @param currency [String, nil] Currency code for the price (e.g., USD, EUR) + # + # @param image_url [String, nil] URL to the product image + # + # @param price [Float, nil] Price of the product + # + # @param pricing_model [Symbol, BrandDev::Models::BrandAIProductResponse::Product::PricingModel, nil] Pricing model for the product + # + # @param url [String, nil] URL to the product page + + # Billing frequency for the product + # + # @see BrandDev::Models::BrandAIProductResponse::Product#billing_frequency + module BillingFrequency + extend BrandDev::Internal::Type::Enum + + MONTHLY = :monthly + YEARLY = :yearly + ONE_TIME = :one_time + USAGE_BASED = :usage_based + + # @!method self.values + # @return [Array] + end + + # Pricing model for the product + # + # @see BrandDev::Models::BrandAIProductResponse::Product#pricing_model + module PricingModel + extend BrandDev::Internal::Type::Enum + + PER_SEAT = :per_seat + FLAT = :flat + TIERED = :tiered + FREEMIUM = :freemium + CUSTOM = :custom + + # @!method self.values + # @return [Array] + end + end + end + end +end diff --git a/lib/brand_dev/resources/brand.rb b/lib/brand_dev/resources/brand.rb index e846d79..11d7fa1 100644 --- a/lib/brand_dev/resources/brand.rb +++ b/lib/brand_dev/resources/brand.rb @@ -35,6 +35,35 @@ def retrieve(params) ) end + # Some parameter documentations has been truncated, see + # {BrandDev::Models::BrandAIProductParams} for more details. + # + # 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. + # + # @overload ai_product(url:, timeout_ms: nil, request_options: {}) + # + # @param url [String] The product page URL to extract product data from. + # + # @param timeout_ms [Integer] Optional timeout in milliseconds for the request. Maximum allowed value is 30000 + # + # @param request_options [BrandDev::RequestOptions, Hash{Symbol=>Object}, nil] + # + # @return [BrandDev::Models::BrandAIProductResponse] + # + # @see BrandDev::Models::BrandAIProductParams + def ai_product(params) + parsed, options = BrandDev::BrandAIProductParams.dump_request(params) + @client.request( + method: :post, + path: "brand/ai/product", + body: parsed, + model: BrandDev::Models::BrandAIProductResponse, + options: options + ) + end + # Some parameter documentations has been truncated, see # {BrandDev::Models::BrandAIProductsParams} for more details. # diff --git a/rbi/brand_dev/models.rbi b/rbi/brand_dev/models.rbi index 2d844b9..b7f8e4f 100644 --- a/rbi/brand_dev/models.rbi +++ b/rbi/brand_dev/models.rbi @@ -1,6 +1,8 @@ # typed: strong module BrandDev + BrandAIProductParams = BrandDev::Models::BrandAIProductParams + BrandAIProductsParams = BrandDev::Models::BrandAIProductsParams BrandAIQueryParams = BrandDev::Models::BrandAIQueryParams diff --git a/rbi/brand_dev/models/brand_ai_product_params.rbi b/rbi/brand_dev/models/brand_ai_product_params.rbi new file mode 100644 index 0000000..509b118 --- /dev/null +++ b/rbi/brand_dev/models/brand_ai_product_params.rbi @@ -0,0 +1,56 @@ +# typed: strong + +module BrandDev + module Models + class BrandAIProductParams < BrandDev::Internal::Type::BaseModel + extend BrandDev::Internal::Type::RequestParameters::Converter + include BrandDev::Internal::Type::RequestParameters + + OrHash = + T.type_alias do + T.any(BrandDev::BrandAIProductParams, BrandDev::Internal::AnyHash) + end + + # The product page URL to extract product data from. + sig { returns(String) } + attr_accessor :url + + # Optional timeout in milliseconds for the request. Maximum allowed value is + # 300000ms (5 minutes). + sig { returns(T.nilable(Integer)) } + attr_reader :timeout_ms + + sig { params(timeout_ms: Integer).void } + attr_writer :timeout_ms + + sig do + params( + url: String, + timeout_ms: Integer, + request_options: BrandDev::RequestOptions::OrHash + ).returns(T.attached_class) + end + def self.new( + # The product page URL to extract product data from. + url:, + # Optional timeout in milliseconds for the request. Maximum allowed value is + # 300000ms (5 minutes). + timeout_ms: nil, + request_options: {} + ) + end + + sig do + override.returns( + { + url: String, + timeout_ms: Integer, + request_options: BrandDev::RequestOptions + } + ) + end + def to_hash + end + end + end +end diff --git a/rbi/brand_dev/models/brand_ai_product_response.rbi b/rbi/brand_dev/models/brand_ai_product_response.rbi new file mode 100644 index 0000000..c9f718d --- /dev/null +++ b/rbi/brand_dev/models/brand_ai_product_response.rbi @@ -0,0 +1,368 @@ +# typed: strong + +module BrandDev + module Models + class BrandAIProductResponse < BrandDev::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + BrandDev::Models::BrandAIProductResponse, + BrandDev::Internal::AnyHash + ) + end + + # Whether the given URL is a product detail page + sig { returns(T.nilable(T::Boolean)) } + attr_reader :is_product_page + + sig { params(is_product_page: T::Boolean).void } + attr_writer :is_product_page + + # The detected ecommerce platform, or null if not a product page + sig do + returns( + T.nilable( + BrandDev::Models::BrandAIProductResponse::Platform::TaggedSymbol + ) + ) + end + attr_accessor :platform + + # The extracted product data, or null if not a product page + sig do + returns(T.nilable(BrandDev::Models::BrandAIProductResponse::Product)) + end + attr_reader :product + + sig do + params( + product: + T.nilable(BrandDev::Models::BrandAIProductResponse::Product::OrHash) + ).void + end + attr_writer :product + + sig do + params( + is_product_page: T::Boolean, + platform: + T.nilable( + BrandDev::Models::BrandAIProductResponse::Platform::OrSymbol + ), + product: + T.nilable(BrandDev::Models::BrandAIProductResponse::Product::OrHash) + ).returns(T.attached_class) + end + def self.new( + # Whether the given URL is a product detail page + is_product_page: nil, + # The detected ecommerce platform, or null if not a product page + platform: nil, + # The extracted product data, or null if not a product page + product: nil + ) + end + + sig do + override.returns( + { + is_product_page: T::Boolean, + platform: + T.nilable( + BrandDev::Models::BrandAIProductResponse::Platform::TaggedSymbol + ), + product: + T.nilable(BrandDev::Models::BrandAIProductResponse::Product) + } + ) + end + def to_hash + end + + # The detected ecommerce platform, or null if not a product page + module Platform + extend BrandDev::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all(Symbol, BrandDev::Models::BrandAIProductResponse::Platform) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + AMAZON = + T.let( + :amazon, + BrandDev::Models::BrandAIProductResponse::Platform::TaggedSymbol + ) + TIKTOK_SHOP = + T.let( + :tiktok_shop, + BrandDev::Models::BrandAIProductResponse::Platform::TaggedSymbol + ) + ETSY = + T.let( + :etsy, + BrandDev::Models::BrandAIProductResponse::Platform::TaggedSymbol + ) + GENERIC = + T.let( + :generic, + BrandDev::Models::BrandAIProductResponse::Platform::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + BrandDev::Models::BrandAIProductResponse::Platform::TaggedSymbol + ] + ) + end + def self.values + end + end + + class Product < BrandDev::Internal::Type::BaseModel + OrHash = + T.type_alias do + T.any( + BrandDev::Models::BrandAIProductResponse::Product, + BrandDev::Internal::AnyHash + ) + end + + # Description of the product + sig { returns(String) } + attr_accessor :description + + # List of product features + sig { returns(T::Array[String]) } + attr_accessor :features + + # Name of the product + sig { returns(String) } + attr_accessor :name + + # Tags associated with the product + sig { returns(T::Array[String]) } + attr_accessor :tags + + # Target audience for the product (array of strings) + sig { returns(T::Array[String]) } + attr_accessor :target_audience + + # Billing frequency for the product + sig do + returns( + T.nilable( + BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency::TaggedSymbol + ) + ) + end + attr_accessor :billing_frequency + + # Category of the product + sig { returns(T.nilable(String)) } + attr_accessor :category + + # Currency code for the price (e.g., USD, EUR) + sig { returns(T.nilable(String)) } + attr_accessor :currency + + # URL to the product image + sig { returns(T.nilable(String)) } + attr_accessor :image_url + + # Price of the product + sig { returns(T.nilable(Float)) } + attr_accessor :price + + # Pricing model for the product + sig do + returns( + T.nilable( + BrandDev::Models::BrandAIProductResponse::Product::PricingModel::TaggedSymbol + ) + ) + end + attr_accessor :pricing_model + + # URL to the product page + sig { returns(T.nilable(String)) } + attr_accessor :url + + # The extracted product data, or null if not a product page + sig do + params( + description: String, + features: T::Array[String], + name: String, + tags: T::Array[String], + target_audience: T::Array[String], + billing_frequency: + T.nilable( + BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency::OrSymbol + ), + category: T.nilable(String), + currency: T.nilable(String), + image_url: T.nilable(String), + price: T.nilable(Float), + pricing_model: + T.nilable( + BrandDev::Models::BrandAIProductResponse::Product::PricingModel::OrSymbol + ), + url: T.nilable(String) + ).returns(T.attached_class) + end + def self.new( + # Description of the product + description:, + # List of product features + features:, + # Name of the product + name:, + # Tags associated with the product + tags:, + # Target audience for the product (array of strings) + target_audience:, + # Billing frequency for the product + billing_frequency: nil, + # Category of the product + category: nil, + # Currency code for the price (e.g., USD, EUR) + currency: nil, + # URL to the product image + image_url: nil, + # Price of the product + price: nil, + # Pricing model for the product + pricing_model: nil, + # URL to the product page + url: nil + ) + end + + sig do + override.returns( + { + description: String, + features: T::Array[String], + name: String, + tags: T::Array[String], + target_audience: T::Array[String], + billing_frequency: + T.nilable( + BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency::TaggedSymbol + ), + category: T.nilable(String), + currency: T.nilable(String), + image_url: T.nilable(String), + price: T.nilable(Float), + pricing_model: + T.nilable( + BrandDev::Models::BrandAIProductResponse::Product::PricingModel::TaggedSymbol + ), + url: T.nilable(String) + } + ) + end + def to_hash + end + + # Billing frequency for the product + module BillingFrequency + extend BrandDev::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + MONTHLY = + T.let( + :monthly, + BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency::TaggedSymbol + ) + YEARLY = + T.let( + :yearly, + BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency::TaggedSymbol + ) + ONE_TIME = + T.let( + :one_time, + BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency::TaggedSymbol + ) + USAGE_BASED = + T.let( + :usage_based, + BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + BrandDev::Models::BrandAIProductResponse::Product::BillingFrequency::TaggedSymbol + ] + ) + end + def self.values + end + end + + # Pricing model for the product + module PricingModel + extend BrandDev::Internal::Type::Enum + + TaggedSymbol = + T.type_alias do + T.all( + Symbol, + BrandDev::Models::BrandAIProductResponse::Product::PricingModel + ) + end + OrSymbol = T.type_alias { T.any(Symbol, String) } + + PER_SEAT = + T.let( + :per_seat, + BrandDev::Models::BrandAIProductResponse::Product::PricingModel::TaggedSymbol + ) + FLAT = + T.let( + :flat, + BrandDev::Models::BrandAIProductResponse::Product::PricingModel::TaggedSymbol + ) + TIERED = + T.let( + :tiered, + BrandDev::Models::BrandAIProductResponse::Product::PricingModel::TaggedSymbol + ) + FREEMIUM = + T.let( + :freemium, + BrandDev::Models::BrandAIProductResponse::Product::PricingModel::TaggedSymbol + ) + CUSTOM = + T.let( + :custom, + BrandDev::Models::BrandAIProductResponse::Product::PricingModel::TaggedSymbol + ) + + sig do + override.returns( + T::Array[ + BrandDev::Models::BrandAIProductResponse::Product::PricingModel::TaggedSymbol + ] + ) + end + def self.values + end + end + end + end + end +end diff --git a/rbi/brand_dev/resources/brand.rbi b/rbi/brand_dev/resources/brand.rbi index 8c1871b..7ff202a 100644 --- a/rbi/brand_dev/resources/brand.rbi +++ b/rbi/brand_dev/resources/brand.rbi @@ -34,6 +34,26 @@ module BrandDev ) end + # 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. + sig do + params( + url: String, + timeout_ms: Integer, + request_options: BrandDev::RequestOptions::OrHash + ).returns(BrandDev::Models::BrandAIProductResponse) + end + def ai_product( + # The product page URL to extract product data from. + url:, + # Optional timeout in milliseconds for the request. Maximum allowed value is + # 300000ms (5 minutes). + timeout_ms: nil, + request_options: {} + ) + end + # Beta feature: Extract product information from a brand's website. Brand.dev will # analyze the website and return a list of products with details such as name, # description, image, pricing, features, and more. diff --git a/sig/brand_dev/models.rbs b/sig/brand_dev/models.rbs index 404791e..2690500 100644 --- a/sig/brand_dev/models.rbs +++ b/sig/brand_dev/models.rbs @@ -1,4 +1,6 @@ module BrandDev + class BrandAIProductParams = BrandDev::Models::BrandAIProductParams + class BrandAIProductsParams = BrandDev::Models::BrandAIProductsParams class BrandAIQueryParams = BrandDev::Models::BrandAIQueryParams diff --git a/sig/brand_dev/models/brand_ai_product_params.rbs b/sig/brand_dev/models/brand_ai_product_params.rbs new file mode 100644 index 0000000..d3c1a3c --- /dev/null +++ b/sig/brand_dev/models/brand_ai_product_params.rbs @@ -0,0 +1,30 @@ +module BrandDev + module Models + type brand_ai_product_params = + { url: String, timeout_ms: Integer } + & BrandDev::Internal::Type::request_parameters + + class BrandAIProductParams < BrandDev::Internal::Type::BaseModel + extend BrandDev::Internal::Type::RequestParameters::Converter + include BrandDev::Internal::Type::RequestParameters + + attr_accessor url: String + + attr_reader timeout_ms: Integer? + + def timeout_ms=: (Integer) -> Integer + + def initialize: ( + url: String, + ?timeout_ms: Integer, + ?request_options: BrandDev::request_opts + ) -> void + + def to_hash: -> { + url: String, + timeout_ms: Integer, + request_options: BrandDev::RequestOptions + } + end + end +end diff --git a/sig/brand_dev/models/brand_ai_product_response.rbs b/sig/brand_dev/models/brand_ai_product_response.rbs new file mode 100644 index 0000000..c1878d9 --- /dev/null +++ b/sig/brand_dev/models/brand_ai_product_response.rbs @@ -0,0 +1,144 @@ +module BrandDev + module Models + type brand_ai_product_response = + { + is_product_page: bool, + platform: BrandDev::Models::BrandAIProductResponse::platform?, + product: BrandDev::Models::BrandAIProductResponse::Product? + } + + class BrandAIProductResponse < BrandDev::Internal::Type::BaseModel + attr_reader is_product_page: bool? + + def is_product_page=: (bool) -> bool + + attr_accessor platform: BrandDev::Models::BrandAIProductResponse::platform? + + attr_accessor product: BrandDev::Models::BrandAIProductResponse::Product? + + def initialize: ( + ?is_product_page: bool, + ?platform: BrandDev::Models::BrandAIProductResponse::platform?, + ?product: BrandDev::Models::BrandAIProductResponse::Product? + ) -> void + + def to_hash: -> { + is_product_page: bool, + platform: BrandDev::Models::BrandAIProductResponse::platform?, + product: BrandDev::Models::BrandAIProductResponse::Product? + } + + type platform = :amazon | :tiktok_shop | :etsy | :generic + + module Platform + extend BrandDev::Internal::Type::Enum + + AMAZON: :amazon + TIKTOK_SHOP: :tiktok_shop + ETSY: :etsy + GENERIC: :generic + + def self?.values: -> ::Array[BrandDev::Models::BrandAIProductResponse::platform] + end + + type product = + { + description: String, + features: ::Array[String], + name: String, + tags: ::Array[String], + target_audience: ::Array[String], + billing_frequency: BrandDev::Models::BrandAIProductResponse::Product::billing_frequency?, + category: String?, + currency: String?, + image_url: String?, + price: Float?, + pricing_model: BrandDev::Models::BrandAIProductResponse::Product::pricing_model?, + url: String? + } + + class Product < BrandDev::Internal::Type::BaseModel + attr_accessor description: String + + attr_accessor features: ::Array[String] + + attr_accessor name: String + + attr_accessor tags: ::Array[String] + + attr_accessor target_audience: ::Array[String] + + attr_accessor billing_frequency: BrandDev::Models::BrandAIProductResponse::Product::billing_frequency? + + attr_accessor category: String? + + attr_accessor currency: String? + + attr_accessor image_url: String? + + attr_accessor price: Float? + + attr_accessor pricing_model: BrandDev::Models::BrandAIProductResponse::Product::pricing_model? + + attr_accessor url: String? + + def initialize: ( + description: String, + features: ::Array[String], + name: String, + tags: ::Array[String], + target_audience: ::Array[String], + ?billing_frequency: BrandDev::Models::BrandAIProductResponse::Product::billing_frequency?, + ?category: String?, + ?currency: String?, + ?image_url: String?, + ?price: Float?, + ?pricing_model: BrandDev::Models::BrandAIProductResponse::Product::pricing_model?, + ?url: String? + ) -> void + + def to_hash: -> { + description: String, + features: ::Array[String], + name: String, + tags: ::Array[String], + target_audience: ::Array[String], + billing_frequency: BrandDev::Models::BrandAIProductResponse::Product::billing_frequency?, + category: String?, + currency: String?, + image_url: String?, + price: Float?, + pricing_model: BrandDev::Models::BrandAIProductResponse::Product::pricing_model?, + url: String? + } + + type billing_frequency = :monthly | :yearly | :one_time | :usage_based + + module BillingFrequency + extend BrandDev::Internal::Type::Enum + + MONTHLY: :monthly + YEARLY: :yearly + ONE_TIME: :one_time + USAGE_BASED: :usage_based + + def self?.values: -> ::Array[BrandDev::Models::BrandAIProductResponse::Product::billing_frequency] + end + + type pricing_model = :per_seat | :flat | :tiered | :freemium | :custom + + module PricingModel + extend BrandDev::Internal::Type::Enum + + PER_SEAT: :per_seat + FLAT: :flat + TIERED: :tiered + FREEMIUM: :freemium + CUSTOM: :custom + + def self?.values: -> ::Array[BrandDev::Models::BrandAIProductResponse::Product::pricing_model] + end + end + end + end +end diff --git a/sig/brand_dev/resources/brand.rbs b/sig/brand_dev/resources/brand.rbs index c315c4e..f591b56 100644 --- a/sig/brand_dev/resources/brand.rbs +++ b/sig/brand_dev/resources/brand.rbs @@ -9,6 +9,12 @@ module BrandDev ?request_options: BrandDev::request_opts ) -> BrandDev::Models::BrandRetrieveResponse + def ai_product: ( + url: String, + ?timeout_ms: Integer, + ?request_options: BrandDev::request_opts + ) -> BrandDev::Models::BrandAIProductResponse + def ai_products: ( domain: String, direct_url: String, diff --git a/test/brand_dev/resources/brand_test.rb b/test/brand_dev/resources/brand_test.rb index 22afe6e..225d605 100644 --- a/test/brand_dev/resources/brand_test.rb +++ b/test/brand_dev/resources/brand_test.rb @@ -21,6 +21,24 @@ def test_retrieve_required_params end end + def test_ai_product_required_params + skip("Prism tests are disabled") + + response = @brand_dev.brand.ai_product(url: "https://example.com") + + assert_pattern do + response => BrandDev::Models::BrandAIProductResponse + end + + assert_pattern do + response => { + is_product_page: BrandDev::Internal::Type::Boolean | nil, + platform: BrandDev::Models::BrandAIProductResponse::Platform | nil, + product: BrandDev::Models::BrandAIProductResponse::Product | nil + } + end + end + def test_ai_products_required_params skip("Prism tests are disabled") From ed1e105ba7333d513d24fa406fe3ef7d67102446 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 9 Feb 2026 02:00:50 +0000 Subject: [PATCH 3/3] release: 0.24.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ Gemfile.lock | 2 +- README.md | 2 +- lib/brand_dev/version.rb | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 7f3f5c8..d2d60a3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.23.0" + ".": "0.24.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 89a946d..ba40918 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.24.0 (2026-02-09) + +Full Changelog: [v0.23.0...v0.24.0](https://github.com/brand-dot-dev/ruby-sdk/compare/v0.23.0...v0.24.0) + +### Features + +* **api:** manual updates ([d51dcea](https://github.com/brand-dot-dev/ruby-sdk/commit/d51dcea705ad031b9010a391b7ed3a26c115beab)) + ## 0.23.0 (2026-02-07) Full Changelog: [v0.22.0...v0.23.0](https://github.com/brand-dot-dev/ruby-sdk/compare/v0.22.0...v0.23.0) diff --git a/Gemfile.lock b/Gemfile.lock index f3fc938..b8d2626 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,7 +11,7 @@ GIT PATH remote: . specs: - brand.dev (0.23.0) + brand.dev (0.24.0) cgi connection_pool diff --git a/README.md b/README.md index cfdf62e..e090c66 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ To use this gem, install via Bundler by adding the following to your application ```ruby -gem "brand.dev", "~> 0.23.0" +gem "brand.dev", "~> 0.24.0" ``` diff --git a/lib/brand_dev/version.rb b/lib/brand_dev/version.rb index 6a39158..65adf76 100644 --- a/lib/brand_dev/version.rb +++ b/lib/brand_dev/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module BrandDev - VERSION = "0.23.0" + VERSION = "0.24.0" end