diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d1328ca..64f9ff4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.7.0" + ".": "2.8.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 3b484e3..74e73bc 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 37 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-758c3a2fbd5b7be61c8e6e0ad2e6a5ec30695747bb675960d888c497647d13d7.yml -openapi_spec_hash: 00002d90bde02f67e174368ae470c597 -config_hash: 2bea1743c84d63bd61f8501a6ea63065 +configured_endpoints: 38 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/context-dev/context.dev-155e4761d62255841349c0f8a01b0a9c463ea1d1f2d6c4fd8d1a75c8bef6f226.yml +openapi_spec_hash: ab91f77e7c9d992400cbc7fc8a9e76c1 +config_hash: bff282047fafdad771fb7ec685f56944 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ece4e8..81b6d2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 2.8.0 (2026-08-05) + +Full Changelog: [v2.7.0...v2.8.0](https://github.com/context-dot-dev/context-php-sdk/compare/v2.7.0...v2.8.0) + +### Features + +* **api:** manual updates ([5a35e94](https://github.com/context-dot-dev/context-php-sdk/commit/5a35e9456fbed83f7a6b96ee69c1443974246d2c)) + ## 2.7.0 (2026-08-01) Full Changelog: [v2.6.0...v2.7.0](https://github.com/context-dot-dev/context-php-sdk/compare/v2.6.0...v2.7.0) diff --git a/README.md b/README.md index ecf5ee4..3f9ffb2 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The REST API documentation can be found on [docs.context.dev](https://docs.conte ``` -composer require "context-dev/context-dev-php 2.7.0" +composer require "context-dev/context-dev-php 2.8.0" ``` diff --git a/src/Brand/BrandSearchParams.php b/src/Brand/BrandSearchParams.php new file mode 100644 index 0000000..30c360b --- /dev/null +++ b/src/Brand/BrandSearchParams.php @@ -0,0 +1,102 @@ +|null + * } + */ +final class BrandSearchParams implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + use SdkParams; + + /** + * Search term, matched against brand names and domains by prefix (e.g. 'nike', 'nike.com', 'nik'). + */ + #[Required] + public string $query; + + /** + * Optional comma-separated caller-defined tags for tracking this request. Tags are recorded on the request's usage log and can be used to filter usage on the dashboard usage page. Up to 20 tags, each 1-50 characters. + * + * @var list|null $tags + */ + #[Optional(list: 'string')] + public ?array $tags; + + /** + * `new BrandSearchParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * BrandSearchParams::with(query: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new BrandSearchParams)->withQuery(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list|null $tags + */ + public static function with(string $query, ?array $tags = null): self + { + $self = new self; + + $self['query'] = $query; + + null !== $tags && $self['tags'] = $tags; + + return $self; + } + + /** + * Search term, matched against brand names and domains by prefix (e.g. 'nike', 'nike.com', 'nik'). + */ + public function withQuery(string $query): self + { + $self = clone $this; + $self['query'] = $query; + + return $self; + } + + /** + * Optional comma-separated caller-defined tags for tracking this request. Tags are recorded on the request's usage log and can be used to filter usage on the dashboard usage page. Up to 20 tags, each 1-50 characters. + * + * @param list $tags + */ + public function withTags(array $tags): self + { + $self = clone $this; + $self['tags'] = $tags; + + return $self; + } +} diff --git a/src/Brand/BrandSearchResponse.php b/src/Brand/BrandSearchResponse.php new file mode 100644 index 0000000..24d1cd5 --- /dev/null +++ b/src/Brand/BrandSearchResponse.php @@ -0,0 +1,107 @@ +, + * keyMetadata?: null|KeyMetadata|KeyMetadataShape, + * } + */ +final class BrandSearchResponse implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Up to 10 matching brands, most popular first. Empty when nothing matches. + * + * @var list $results + */ + #[Required(list: Result::class)] + public array $results; + + /** + * Metadata about the API key used for the request. Included in every response whenever a valid API key is provided, even when the response status is not 200. + */ + #[Optional('key_metadata')] + public ?KeyMetadata $keyMetadata; + + /** + * `new BrandSearchResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * BrandSearchResponse::with(results: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new BrandSearchResponse)->withResults(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list $results + * @param KeyMetadata|KeyMetadataShape|null $keyMetadata + */ + public static function with( + array $results, + KeyMetadata|array|null $keyMetadata = null + ): self { + $self = new self; + + $self['results'] = $results; + + null !== $keyMetadata && $self['keyMetadata'] = $keyMetadata; + + return $self; + } + + /** + * Up to 10 matching brands, most popular first. Empty when nothing matches. + * + * @param list $results + */ + public function withResults(array $results): self + { + $self = clone $this; + $self['results'] = $results; + + return $self; + } + + /** + * Metadata about the API key used for the request. Included in every response whenever a valid API key is provided, even when the response status is not 200. + * + * @param KeyMetadata|KeyMetadataShape $keyMetadata + */ + public function withKeyMetadata(KeyMetadata|array $keyMetadata): self + { + $self = clone $this; + $self['keyMetadata'] = $keyMetadata; + + return $self; + } +} diff --git a/src/Brand/BrandSearchResponse/KeyMetadata.php b/src/Brand/BrandSearchResponse/KeyMetadata.php new file mode 100644 index 0000000..aee2ec5 --- /dev/null +++ b/src/Brand/BrandSearchResponse/KeyMetadata.php @@ -0,0 +1,92 @@ + */ + use SdkModel; + + /** + * The number of credits consumed by this request. + */ + #[Required('credits_consumed')] + public int $creditsConsumed; + + /** + * The number of credits remaining for your organization after this request. + */ + #[Required('credits_remaining')] + public int $creditsRemaining; + + /** + * `new KeyMetadata()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * KeyMetadata::with(creditsConsumed: ..., creditsRemaining: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new KeyMetadata)->withCreditsConsumed(...)->withCreditsRemaining(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + int $creditsConsumed, + int $creditsRemaining + ): self { + $self = new self; + + $self['creditsConsumed'] = $creditsConsumed; + $self['creditsRemaining'] = $creditsRemaining; + + return $self; + } + + /** + * The number of credits consumed by this request. + */ + public function withCreditsConsumed(int $creditsConsumed): self + { + $self = clone $this; + $self['creditsConsumed'] = $creditsConsumed; + + return $self; + } + + /** + * The number of credits remaining for your organization after this request. + */ + public function withCreditsRemaining(int $creditsRemaining): self + { + $self = clone $this; + $self['creditsRemaining'] = $creditsRemaining; + + return $self; + } +} diff --git a/src/Brand/BrandSearchResponse/Result.php b/src/Brand/BrandSearchResponse/Result.php new file mode 100644 index 0000000..347d6b8 --- /dev/null +++ b/src/Brand/BrandSearchResponse/Result.php @@ -0,0 +1,107 @@ + */ + use SdkModel; + + /** + * The brand's domain. + */ + #[Required] + public string $domain; + + /** + * Logo link URL that serves the brand's logo, generated per request for the calling organization. + */ + #[Required] + public string $logo; + + /** + * The brand's name. Empty string when unknown. + */ + #[Required] + public string $name; + + /** + * `new Result()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Result::with(domain: ..., logo: ..., name: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Result)->withDomain(...)->withLogo(...)->withName(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $domain, + string $logo, + string $name + ): self { + $self = new self; + + $self['domain'] = $domain; + $self['logo'] = $logo; + $self['name'] = $name; + + return $self; + } + + /** + * The brand's domain. + */ + public function withDomain(string $domain): self + { + $self = clone $this; + $self['domain'] = $domain; + + return $self; + } + + /** + * Logo link URL that serves the brand's logo, generated per request for the calling organization. + */ + public function withLogo(string $logo): self + { + $self = clone $this; + $self['logo'] = $logo; + + return $self; + } + + /** + * The brand's name. Empty string when unknown. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } +} diff --git a/src/ServiceContracts/BrandContract.php b/src/ServiceContracts/BrandContract.php index ce818d8..406ec4d 100644 --- a/src/ServiceContracts/BrandContract.php +++ b/src/ServiceContracts/BrandContract.php @@ -9,6 +9,7 @@ use ContextDev\Brand\BrandRetrieveParams\ForceLanguage; use ContextDev\Brand\BrandRetrieveParams\Type; use ContextDev\Brand\BrandRetrieveSimplifiedParams\Theme; +use ContextDev\Brand\BrandSearchResponse; use ContextDev\Core\Exceptions\APIException; use ContextDev\RequestOptions; @@ -86,4 +87,19 @@ public function retrieveSimplified( ?int $timeoutMs = null, RequestOptions|array|null $requestOptions = null, ): BrandGetSimplifiedResponse; + + /** + * @api + * + * @param string $query Search term, matched against brand names and domains by prefix (e.g. 'nike', 'nike.com', 'nik'). + * @param list $tags Optional comma-separated caller-defined tags for tracking this request. Tags are recorded on the request's usage log and can be used to filter usage on the dashboard usage page. Up to 20 tags, each 1-50 characters. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function search( + string $query, + ?array $tags = null, + RequestOptions|array|null $requestOptions = null, + ): BrandSearchResponse; } diff --git a/src/ServiceContracts/BrandRawContract.php b/src/ServiceContracts/BrandRawContract.php index 784eff7..0f747ff 100644 --- a/src/ServiceContracts/BrandRawContract.php +++ b/src/ServiceContracts/BrandRawContract.php @@ -8,6 +8,8 @@ use ContextDev\Brand\BrandGetSimplifiedResponse; use ContextDev\Brand\BrandRetrieveParams; use ContextDev\Brand\BrandRetrieveSimplifiedParams; +use ContextDev\Brand\BrandSearchParams; +use ContextDev\Brand\BrandSearchResponse; use ContextDev\Core\Contracts\BaseResponse; use ContextDev\Core\Exceptions\APIException; use ContextDev\RequestOptions; @@ -46,4 +48,19 @@ public function retrieveSimplified( array|BrandRetrieveSimplifiedParams $params, RequestOptions|array|null $requestOptions = null, ): BaseResponse; + + /** + * @api + * + * @param array|BrandSearchParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function search( + array|BrandSearchParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; } diff --git a/src/Services/BrandRawService.php b/src/Services/BrandRawService.php index 7796a7d..fdb05fd 100644 --- a/src/Services/BrandRawService.php +++ b/src/Services/BrandRawService.php @@ -11,6 +11,8 @@ use ContextDev\Brand\BrandRetrieveParams\Type; use ContextDev\Brand\BrandRetrieveSimplifiedParams; use ContextDev\Brand\BrandRetrieveSimplifiedParams\Theme; +use ContextDev\Brand\BrandSearchParams; +use ContextDev\Brand\BrandSearchResponse; use ContextDev\Client; use ContextDev\Core\Contracts\BaseResponse; use ContextDev\Core\Exceptions\APIException; @@ -117,4 +119,35 @@ public function retrieveSimplified( convert: BrandGetSimplifiedResponse::class, ); } + + /** + * @api + * + * Search brands by name or domain and get back up to 10 lightweight matches (domain, name, logo), most popular first: by Tranco rank, then market cap for brands outside the Tranco list, with text relevance breaking ties. Matching is prefix-based with no typo tolerance, so it is suited to autocomplete. Only brands already in the Context.dev index are returned — use /brand/retrieve to fetch (and index) a specific domain. Free on Pro and Scale plans; costs 1 credit per request on the Free and Starter plans. + * + * @param array{query: string, tags?: list}|BrandSearchParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function search( + array|BrandSearchParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = BrandSearchParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: 'brand/search', + query: $parsed, + options: $options, + convert: BrandSearchResponse::class, + ); + } } diff --git a/src/Services/BrandService.php b/src/Services/BrandService.php index 0ab38c5..fc9c8ee 100644 --- a/src/Services/BrandService.php +++ b/src/Services/BrandService.php @@ -9,6 +9,7 @@ use ContextDev\Brand\BrandRetrieveParams\ForceLanguage; use ContextDev\Brand\BrandRetrieveParams\Type; use ContextDev\Brand\BrandRetrieveSimplifiedParams\Theme; +use ContextDev\Brand\BrandSearchResponse; use ContextDev\Client; use ContextDev\Core\Exceptions\APIException; use ContextDev\Core\Util; @@ -149,4 +150,28 @@ public function retrieveSimplified( return $response->parse(); } + + /** + * @api + * + * Search brands by name or domain and get back up to 10 lightweight matches (domain, name, logo), most popular first: by Tranco rank, then market cap for brands outside the Tranco list, with text relevance breaking ties. Matching is prefix-based with no typo tolerance, so it is suited to autocomplete. Only brands already in the Context.dev index are returned — use /brand/retrieve to fetch (and index) a specific domain. Free on Pro and Scale plans; costs 1 credit per request on the Free and Starter plans. + * + * @param string $query Search term, matched against brand names and domains by prefix (e.g. 'nike', 'nike.com', 'nik'). + * @param list $tags Optional comma-separated caller-defined tags for tracking this request. Tags are recorded on the request's usage log and can be used to filter usage on the dashboard usage page. Up to 20 tags, each 1-50 characters. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function search( + string $query, + ?array $tags = null, + RequestOptions|array|null $requestOptions = null, + ): BrandSearchResponse { + $params = Util::removeNulls(['query' => $query, 'tags' => $tags]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->search(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } } diff --git a/src/Version.php b/src/Version.php index 5d54e5f..9050d10 100644 --- a/src/Version.php +++ b/src/Version.php @@ -5,5 +5,5 @@ namespace ContextDev; // x-release-please-start-version -const VERSION = '2.7.0'; +const VERSION = '2.8.0'; // x-release-please-end diff --git a/tests/Services/BrandTest.php b/tests/Services/BrandTest.php index b5ab8fc..e59d219 100644 --- a/tests/Services/BrandTest.php +++ b/tests/Services/BrandTest.php @@ -4,6 +4,7 @@ use ContextDev\Brand\BrandGetResponse; use ContextDev\Brand\BrandGetSimplifiedResponse; +use ContextDev\Brand\BrandSearchResponse; use ContextDev\Client; use ContextDev\Core\Util; use PHPUnit\Framework\Attributes\CoversNothing; @@ -113,4 +114,33 @@ public function testRetrieveSimplifiedWithOptionalParams(): void // @phpstan-ignore-next-line method.alreadyNarrowedType $this->assertInstanceOf(BrandGetSimplifiedResponse::class, $result); } + + #[Test] + public function testSearch(): void + { + if (UnsupportedMockTests::$skip) { + $this->markTestSkipped('Mock server tests are disabled'); + } + + $result = $this->client->brand->search(query: 'x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(BrandSearchResponse::class, $result); + } + + #[Test] + public function testSearchWithOptionalParams(): void + { + if (UnsupportedMockTests::$skip) { + $this->markTestSkipped('Mock server tests are disabled'); + } + + $result = $this->client->brand->search( + query: 'x', + tags: ['production', 'team-alpha'] + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(BrandSearchResponse::class, $result); + } }