Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.32.0"
".": "0.33.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 27
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/moderation-api/moderation-api-2ef54d84ceaaff07aaed2e027c1107c7df1d9885766a080d4d965e5ed49a295b.yml
openapi_spec_hash: 48908ecb83e4027405172a62d5a1638b
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/moderation-api/moderation-api-984af2e010ad1bf22f607ee96f27260ecf421c0ce5664839799b92eb349f9255.yml
openapi_spec_hash: bbd9dbdc1a4b7b0ad35aa08fba66e676
config_hash: 9d144cc6c49d3fd53e5b4472c1e22165
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 0.33.0 (2026-08-14)

Full Changelog: [v0.32.0...v0.33.0](https://github.com/moderation-api/sdk-php/compare/v0.32.0...v0.33.0)

### Features

* **api:** api update ([646aee0](https://github.com/moderation-api/sdk-php/commit/646aee0f68dc37fa7496675adf9cc85490f88ace))


### Chores

* **internal:** codegen related update ([510d5b3](https://github.com/moderation-api/sdk-php/commit/510d5b3110e0efdb35edad60b9404f842e154939))

## 0.32.0 (2026-08-13)

Full Changelog: [v0.31.0...v0.32.0](https://github.com/moderation-api/sdk-php/compare/v0.31.0...v0.32.0)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The REST API documentation can be found on [docs.moderationapi.com](https://docs
<!-- x-release-please-start-version -->

```
composer require "moderation-api/sdk-php 0.32.0"
composer require "moderation-api/sdk-php 0.33.0"
```

<!-- x-release-please-end -->
Expand Down
9 changes: 8 additions & 1 deletion src/Core/BaseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use ModerationAPI\Core\Exceptions\APIConnectionException;
use ModerationAPI\Core\Exceptions\APIStatusException;
use ModerationAPI\Core\Implementation\RawResponse;
use ModerationAPI\Core\Implementation\StreamingHttpClient;
use ModerationAPI\RequestOptions;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\RequestInterface;
Expand Down Expand Up @@ -249,7 +250,13 @@ protected function sendRequest(
$err = null;

try {
$rsp = $transporter->sendRequest($req);
if ($transporter instanceof StreamingHttpClient) {
$rsp = $transporter->sendRequest($req, timeout: $opts->timeout);
} elseif (is_a($transporter, '\GuzzleHttp\Client')) {
$rsp = $transporter->send($req, ['timeout' => $opts->timeout]);
} else {
$rsp = $transporter->sendRequest($req);
}
} catch (ClientExceptionInterface $e) {
$err = $e;
}
Expand Down
9 changes: 7 additions & 2 deletions src/Core/Implementation/StreamingHttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ final class StreamingHttpClient implements ClientInterface
{
public function __construct(private ClientInterface $inner) {}

public function sendRequest(RequestInterface $request): ResponseInterface
public function sendRequest(RequestInterface $request, ?float $timeout = null): ResponseInterface
{
if (is_a($this->inner, '\GuzzleHttp\Client')) {
return $this->inner->send($request, ['stream' => true]);
$options = ['stream' => true];
if (null !== $timeout) {
$options['timeout'] = $timeout;
}

return $this->inner->send($request, $options);
}

return $this->inner->sendRequest($request);
Expand Down
28 changes: 28 additions & 0 deletions src/Queue/QueueGetResponse/Queue/Filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
* isFlagged?: null|IsFlagged|value-of<IsFlagged>,
* labels?: list<string>|null,
* languages?: list<string>|null,
* maxSeverity?: int|null,
* mediaTypes?: list<MediaType|value-of<MediaType>>|null,
* minSeverity?: int|null,
* recommendationActions?: list<RecommendationAction|value-of<RecommendationAction>>|null,
* search?: list<string>|null,
* within?: float|null,
Expand Down Expand Up @@ -102,10 +104,16 @@ final class Filter implements BaseModel
#[Optional(list: 'string')]
public ?array $languages;

#[Optional]
public ?int $maxSeverity;

/** @var list<value-of<MediaType>>|null $mediaTypes */
#[Optional(list: MediaType::class)]
public ?array $mediaTypes;

#[Optional]
public ?int $minSeverity;

/** @var list<value-of<RecommendationAction>>|null $recommendationActions */
#[Optional(list: RecommendationAction::class)]
public ?array $recommendationActions;
Expand Down Expand Up @@ -162,7 +170,9 @@ public static function with(
IsFlagged|string|null $isFlagged = null,
?array $labels = null,
?array $languages = null,
?int $maxSeverity = null,
?array $mediaTypes = null,
?int $minSeverity = null,
?array $recommendationActions = null,
?array $search = null,
?float $within = null,
Expand All @@ -185,7 +195,9 @@ public static function with(
null !== $isFlagged && $self['isFlagged'] = $isFlagged;
null !== $labels && $self['labels'] = $labels;
null !== $languages && $self['languages'] = $languages;
null !== $maxSeverity && $self['maxSeverity'] = $maxSeverity;
null !== $mediaTypes && $self['mediaTypes'] = $mediaTypes;
null !== $minSeverity && $self['minSeverity'] = $minSeverity;
null !== $recommendationActions && $self['recommendationActions'] = $recommendationActions;
null !== $search && $self['search'] = $search;
null !== $within && $self['within'] = $within;
Expand Down Expand Up @@ -344,6 +356,14 @@ public function withLanguages(array $languages): self
return $self;
}

public function withMaxSeverity(int $maxSeverity): self
{
$self = clone $this;
$self['maxSeverity'] = $maxSeverity;

return $self;
}

/**
* @param list<MediaType|value-of<MediaType>> $mediaTypes
*/
Expand All @@ -355,6 +375,14 @@ public function withMediaTypes(array $mediaTypes): self
return $self;
}

public function withMinSeverity(int $minSeverity): self
{
$self = clone $this;
$self['minSeverity'] = $minSeverity;

return $self;
}

/**
* @param list<RecommendationAction|value-of<RecommendationAction>> $recommendationActions
*/
Expand Down
2 changes: 1 addition & 1 deletion src/Version.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
namespace ModerationAPI;

// x-release-please-start-version
const VERSION = '0.32.0';
const VERSION = '0.33.0';
// x-release-please-end
81 changes: 81 additions & 0 deletions tests/Core/RequestTimeoutTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace Tests\Core;

use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use Http\Discovery\Psr17FactoryDiscovery;
use ModerationAPI\Core\BaseClient;
use ModerationAPI\Core\Implementation\StreamingHttpClient;
use ModerationAPI\RequestOptions;
use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

/**
* @internal
*
* @coversNothing
*/
#[CoversNothing]
class RequestTimeoutTest extends TestCase
{
#[Test]
public function testPassesPerRequestTimeoutToGuzzleTransporter(): void
{
[$client, $mock] = $this->buildClient();

$client->request('GET', '/', options: ['timeout' => 1.5]);

$this->assertSame(1.5, $mock->getLastOptions()['timeout']);
}

#[Test]
public function testPassesDefaultTimeoutToGuzzleTransporter(): void
{
[$client, $mock] = $this->buildClient();

$client->request('GET', '/');

$this->assertSame((new RequestOptions)->timeout, $mock->getLastOptions()['timeout']);
}

#[Test]
public function testPassesTimeoutToStreamingTransporter(): void
{
[$client, $mock] = $this->buildClient(streaming: true);

$client->request('GET', '/', headers: ['Accept' => 'text/event-stream'], options: ['timeout' => 2.5]);

$options = $mock->getLastOptions();
$this->assertTrue($options['stream']);
$this->assertSame(2.5, $options['timeout']);
}

/**
* @return array{BaseClient, MockHandler}
*/
private function buildClient(bool $streaming = false): array
{
$response = $streaming
? new Response(200, ['Content-Type' => 'text/event-stream'], '')
: new Response(200, ['Content-Type' => 'application/json'], '{}');

$mock = new MockHandler([$response]);
$guzzle = new GuzzleClient(['handler' => HandlerStack::create($mock)]);

$options = RequestOptions::with(
transporter: $guzzle,
streamingTransporter: new StreamingHttpClient($guzzle),
uriFactory: Psr17FactoryDiscovery::findUriFactory(),
requestFactory: Psr17FactoryDiscovery::findRequestFactory(),
streamFactory: Psr17FactoryDiscovery::findStreamFactory(),
);

$client = new class(headers: [], baseUrl: 'http://localhost', options: $options) extends BaseClient {};

return [$client, $mock];
}
}