From 012a381f1fe196affc856402fefb7d58395f5019 Mon Sep 17 00:00:00 2001 From: Michael Broshi Date: Wed, 27 Aug 2025 17:12:08 -0400 Subject: [PATCH 1/3] Add private-preview branch to CI workflow triggers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd5dabb6c..4aa39a85b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ on: branches: - master - beta + - private-preview - sdk-release/** - feature/** From 25be66026c08b5dcfded9881afed5d8e6af00a22 Mon Sep 17 00:00:00 2001 From: David Brownman <109395161+xavdid-stripe@users.noreply.github.com> Date: Fri, 8 Aug 2025 18:22:07 -0700 Subject: [PATCH 2/3] add support for v2 deleted objects (#1889) * add support for v2 deleted objects * Add generated tests * rename arg, pull calculation into function * format --- init.php | 1 + lib/BaseStripeClient.php | 2 +- lib/Util/Util.php | 31 ++++++++++--- lib/V2/DeletedObject.php | 14 ++++++ tests/Stripe/GeneratedExamplesTest.php | 60 ++------------------------ 5 files changed, 45 insertions(+), 63 deletions(-) create mode 100644 lib/V2/DeletedObject.php diff --git a/init.php b/init.php index f37db7613..b45fc188d 100644 --- a/init.php +++ b/init.php @@ -381,6 +381,7 @@ require __DIR__ . '/lib/V2/Billing/MeterEvent.php'; require __DIR__ . '/lib/V2/Billing/MeterEventAdjustment.php'; require __DIR__ . '/lib/V2/Billing/MeterEventSession.php'; +require __DIR__ . '/lib/V2/DeletedObject.php'; require __DIR__ . '/lib/V2/EventDestination.php'; require __DIR__ . '/lib/WebhookEndpoint.php'; diff --git a/lib/BaseStripeClient.php b/lib/BaseStripeClient.php index 2a2714b8a..e6a921f4b 100644 --- a/lib/BaseStripeClient.php +++ b/lib/BaseStripeClient.php @@ -212,7 +212,7 @@ public function request($method, $path, $params, $opts) $requestor = new ApiRequestor($this->apiKeyForRequest($opts), $baseUrl, $this->getAppInfo()); list($response, $opts->apiKey) = $requestor->request($method, $path, $params, $opts->headers, $apiMode, ['stripe_client'], $opts->maxNetworkRetries); $opts->discardNonPersistentHeaders(); - $obj = Util::convertToStripeObject($response->json, $opts, $apiMode); + $obj = Util::convertToStripeObject($response->json, $opts, $apiMode, Util::isV2DeleteRequest($method, $apiMode)); if (\is_array($obj)) { // Edge case for v2 endpoints that return empty/void response // Example: client->v2->billing->meterEventStream->create diff --git a/lib/Util/Util.php b/lib/Util/Util.php index bcf243392..5a6095556 100644 --- a/lib/Util/Util.php +++ b/lib/Util/Util.php @@ -3,6 +3,7 @@ namespace Stripe\Util; use Stripe\StripeObject; +use Stripe\V2\DeletedObject; abstract class Util { @@ -39,10 +40,11 @@ public static function isList($array) * @param array $resp the response from the Stripe API * @param array|RequestOptions $opts * @param 'v1'|'v2' $apiMode whether the response is from a v1 or v2 API + * @param bool $isV2DeletedObject whether we should ignore the `object` field and treat the response as a v2 deleted object * * @return array|StripeObject */ - public static function convertToStripeObject($resp, $opts, $apiMode = 'v1') + public static function convertToStripeObject($resp, $opts, $apiMode = 'v1', $isV2DeletedObject = false) { $types = 'v1' === $apiMode ? ObjectTypes::mapping : ObjectTypes::v2Mapping; @@ -55,7 +57,10 @@ public static function convertToStripeObject($resp, $opts, $apiMode = 'v1') return $mapped; } if (\is_array($resp)) { - if (isset($resp['object']) && \is_string($resp['object']) + if ($isV2DeletedObject) { + $class = DeletedObject::class; + } elseif ( + isset($resp['object']) && \is_string($resp['object']) && isset($types[$resp['object']]) ) { $class = $types[$resp['object']]; @@ -131,15 +136,16 @@ public static function utf8($value) if (!self::$isMbstringAvailable) { \trigger_error( 'It looks like the mbstring extension is not enabled. ' - . 'UTF-8 strings will not properly be encoded. Ask your system ' - . 'administrator to enable the mbstring extension, or write to ' - . 'support@stripe.com if you have any questions.', + . 'UTF-8 strings will not properly be encoded. Ask your system ' + . 'administrator to enable the mbstring extension, or write to ' + . 'support@stripe.com if you have any questions.', \E_USER_WARNING ); } } - if (\is_string($value) && self::$isMbstringAvailable + if ( + \is_string($value) && self::$isMbstringAvailable && 'UTF-8' !== \mb_detect_encoding($value, 'UTF-8', true) ) { return mb_convert_encoding($value, 'UTF-8', 'ISO-8859-1'); @@ -357,4 +363,17 @@ public static function getApiMode($path) return $apiMode; } + + /** + * Useful for determining if we should trust the object type when turning a response into a StripeObject. + * + * @param 'delete'|'get'|'post' $method the HTTP method + * @param 'v1'|'v2' $apiMode the API version + * + * @return bool true if the method is a DELETE request for v2 API, false otherwise + */ + public static function isV2DeleteRequest($method, $apiMode) + { + return 'delete' === $method && 'v2' === $apiMode; + } } diff --git a/lib/V2/DeletedObject.php b/lib/V2/DeletedObject.php new file mode 100644 index 000000000..088e1ef82 --- /dev/null +++ b/lib/V2/DeletedObject.php @@ -0,0 +1,14 @@ + [ 'id' => 'obj_123', 'object' => 'v2.core.event_destination', - 'amazon_eventbridge' => null, 'created' => '1970-01-12T21:42:34.472Z', 'description' => 'description', 'enabled_events' => ['0' => 'enabled_events'], 'event_payload' => 'thin', - 'events_from' => null, 'livemode' => [], - 'metadata' => null, 'name' => 'name', - 'snapshot_api_version' => null, 'status' => 'disabled', - 'status_details' => null, 'type' => 'amazon_eventbridge', 'updated' => '1970-01-03T17:07:10.277Z', - 'webhook_endpoint' => null, ], ], 'next_page_url' => null, @@ -5051,21 +5045,15 @@ public function testV2CoreEventDestinationPost() [ 'id' => 'obj_123', 'object' => 'v2.core.event_destination', - 'amazon_eventbridge' => null, 'created' => '1970-01-12T21:42:34.472Z', 'description' => 'description', 'enabled_events' => ['0' => 'enabled_events'], 'event_payload' => 'thin', - 'events_from' => null, 'livemode' => [], - 'metadata' => null, 'name' => 'name', - 'snapshot_api_version' => null, 'status' => 'disabled', - 'status_details' => null, 'type' => 'amazon_eventbridge', 'updated' => '1970-01-03T17:07:10.277Z', - 'webhook_endpoint' => null, ], 200, BaseStripeClient::DEFAULT_API_BASE @@ -5088,23 +5076,9 @@ public function testV2CoreEventDestinationDelete() [], false, [ - 'id' => 'obj_123', - 'object' => 'v2.core.event_destination', - 'amazon_eventbridge' => null, - 'created' => '1970-01-12T21:42:34.472Z', - 'description' => 'description', - 'enabled_events' => ['0' => 'enabled_events'], - 'event_payload' => 'thin', - 'events_from' => null, - 'livemode' => [], - 'metadata' => null, - 'name' => 'name', - 'snapshot_api_version' => null, - 'status' => 'disabled', - 'status_details' => null, - 'type' => 'amazon_eventbridge', - 'updated' => '1970-01-03T17:07:10.277Z', - 'webhook_endpoint' => null, + 'id' => 'abc_123', + 'object' => 'some.object.tag', + 'deleted' => [], ], 200, BaseStripeClient::DEFAULT_API_BASE @@ -5113,7 +5087,7 @@ public function testV2CoreEventDestinationDelete() 'id_123', [] ); - self::assertInstanceOf(V2\EventDestination::class, $result); + self::assertInstanceOf(V2\DeletedObject::class, $result); } public function testV2CoreEventDestinationGet2() @@ -5127,21 +5101,15 @@ public function testV2CoreEventDestinationGet2() [ 'id' => 'obj_123', 'object' => 'v2.core.event_destination', - 'amazon_eventbridge' => null, 'created' => '1970-01-12T21:42:34.472Z', 'description' => 'description', 'enabled_events' => ['0' => 'enabled_events'], 'event_payload' => 'thin', - 'events_from' => null, 'livemode' => [], - 'metadata' => null, 'name' => 'name', - 'snapshot_api_version' => null, 'status' => 'disabled', - 'status_details' => null, 'type' => 'amazon_eventbridge', 'updated' => '1970-01-03T17:07:10.277Z', - 'webhook_endpoint' => null, ], 200, BaseStripeClient::DEFAULT_API_BASE @@ -5164,21 +5132,15 @@ public function testV2CoreEventDestinationPost2() [ 'id' => 'obj_123', 'object' => 'v2.core.event_destination', - 'amazon_eventbridge' => null, 'created' => '1970-01-12T21:42:34.472Z', 'description' => 'description', 'enabled_events' => ['0' => 'enabled_events'], 'event_payload' => 'thin', - 'events_from' => null, 'livemode' => [], - 'metadata' => null, 'name' => 'name', - 'snapshot_api_version' => null, 'status' => 'disabled', - 'status_details' => null, 'type' => 'amazon_eventbridge', 'updated' => '1970-01-03T17:07:10.277Z', - 'webhook_endpoint' => null, ], 200, BaseStripeClient::DEFAULT_API_BASE @@ -5201,21 +5163,15 @@ public function testV2CoreEventDestinationPost3() [ 'id' => 'obj_123', 'object' => 'v2.core.event_destination', - 'amazon_eventbridge' => null, 'created' => '1970-01-12T21:42:34.472Z', 'description' => 'description', 'enabled_events' => ['0' => 'enabled_events'], 'event_payload' => 'thin', - 'events_from' => null, 'livemode' => [], - 'metadata' => null, 'name' => 'name', - 'snapshot_api_version' => null, 'status' => 'disabled', - 'status_details' => null, 'type' => 'amazon_eventbridge', 'updated' => '1970-01-03T17:07:10.277Z', - 'webhook_endpoint' => null, ], 200, BaseStripeClient::DEFAULT_API_BASE @@ -5238,21 +5194,15 @@ public function testV2CoreEventDestinationPost4() [ 'id' => 'obj_123', 'object' => 'v2.core.event_destination', - 'amazon_eventbridge' => null, 'created' => '1970-01-12T21:42:34.472Z', 'description' => 'description', 'enabled_events' => ['0' => 'enabled_events'], 'event_payload' => 'thin', - 'events_from' => null, 'livemode' => [], - 'metadata' => null, 'name' => 'name', - 'snapshot_api_version' => null, 'status' => 'disabled', - 'status_details' => null, 'type' => 'amazon_eventbridge', 'updated' => '1970-01-03T17:07:10.277Z', - 'webhook_endpoint' => null, ], 200, BaseStripeClient::DEFAULT_API_BASE @@ -5273,11 +5223,9 @@ public function testV2CoreEventDestinationPost5() [], false, [ - 'context' => null, 'created' => '1970-01-12T21:42:34.472Z', 'id' => 'obj_123', 'object' => 'v2.core.event', - 'reason' => null, 'type' => 'type', 'livemode' => [], ], From 205b8f7bf03b1021abf048898ea1846bddb95fb8 Mon Sep 17 00:00:00 2001 From: David Brownman <109395161+xavdid-stripe@users.noreply.github.com> Date: Mon, 8 Sep 2025 08:32:17 -0700 Subject: [PATCH 3/3] generate w/ v2 openapi spec (#1898) --- lib/Service/V2/Core/EventDestinationService.php | 2 +- lib/V2/DeletedObject.php | 2 +- lib/V2/EventDestination.php | 4 ++-- tests/Stripe/GeneratedExamplesTest.php | 4 ---- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/Service/V2/Core/EventDestinationService.php b/lib/Service/V2/Core/EventDestinationService.php index 7524caa63..ce21a54a1 100644 --- a/lib/Service/V2/Core/EventDestinationService.php +++ b/lib/Service/V2/Core/EventDestinationService.php @@ -48,7 +48,7 @@ public function create($params = null, $opts = null) * @param null|array $params * @param null|RequestOptionsArray|\Stripe\Util\RequestOptions $opts * - * @return \Stripe\V2\EventDestination + * @return \Stripe\V2\DeletedObject * * @throws \Stripe\Exception\ApiErrorException if the request fails */ diff --git a/lib/V2/DeletedObject.php b/lib/V2/DeletedObject.php index 088e1ef82..025f431c1 100644 --- a/lib/V2/DeletedObject.php +++ b/lib/V2/DeletedObject.php @@ -6,7 +6,7 @@ /** * @property string $id The ID of the object that's being deleted. - * @property null|string $object String representing the object's type. Objects of the same type share the same value of the object field. + * @property null|string $object String representing the type of the object that has been deleted. Objects of the same type share the same value of the object field. */ class DeletedObject extends \Stripe\ApiResource { diff --git a/lib/V2/EventDestination.php b/lib/V2/EventDestination.php index 21d3c6ae0..eedde4a84 100644 --- a/lib/V2/EventDestination.php +++ b/lib/V2/EventDestination.php @@ -20,10 +20,10 @@ * @property string $name Event destination name. * @property null|string $snapshot_api_version If using the snapshot event payload, the API version events are rendered as. * @property string $status Status. It can be set to either enabled or disabled. - * @property null|(object{disabled: null|(object{reason: string}&\Stripe\StripeObject)}&\Stripe\StripeObject) $status_details Additional information about event destination status. + * @property null|(object{disabled?: (object{reason: string}&\Stripe\StripeObject)}&\Stripe\StripeObject) $status_details Additional information about event destination status. * @property string $type Event destination type. * @property int $updated Time at which the object was last updated. - * @property null|(object{signing_secret: null|string, url: null|string}&\Stripe\StripeObject) $webhook_endpoint Webhook endpoint configuration. + * @property null|(object{signing_secret?: string, url?: string}&\Stripe\StripeObject) $webhook_endpoint Webhook endpoint configuration. */ class EventDestination extends \Stripe\ApiResource { diff --git a/tests/Stripe/GeneratedExamplesTest.php b/tests/Stripe/GeneratedExamplesTest.php index c8f10201b..ca582a00c 100644 --- a/tests/Stripe/GeneratedExamplesTest.php +++ b/tests/Stripe/GeneratedExamplesTest.php @@ -4948,11 +4948,9 @@ public function testV2CoreEventGet() [ 'data' => [ '0' => [ - 'context' => null, 'created' => '1970-01-12T21:42:34.472Z', 'id' => 'obj_123', 'object' => 'v2.core.event', - 'reason' => null, 'type' => 'type', 'livemode' => [], ], @@ -4979,11 +4977,9 @@ public function testV2CoreEventGet2() [], false, [ - 'context' => null, 'created' => '1970-01-12T21:42:34.472Z', 'id' => 'obj_123', 'object' => 'v2.core.event', - 'reason' => null, 'type' => 'type', 'livemode' => [], ],