From d0cb5a4d8b897ab8309b3dc393a45b4a24a3907b Mon Sep 17 00:00:00 2001 From: benjamineckstein <13351939+benjamineckstein@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:56:59 +0200 Subject: [PATCH 1/2] feat(server): emit @deprecated docblock on controller methods for deprecated operations --- src/Emitter/Server/ControllerGenerator.php | 9 +++ src/Emitter/Server/OperationCollector.php | 1 + src/Emitter/Server/OperationDescriptor.php | 9 +++ .../Server/DeprecatedOperationTest.php | 81 +++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 tests/Unit/Emitter/Server/DeprecatedOperationTest.php diff --git a/src/Emitter/Server/ControllerGenerator.php b/src/Emitter/Server/ControllerGenerator.php index 2251cd3..8461aee 100644 --- a/src/Emitter/Server/ControllerGenerator.php +++ b/src/Emitter/Server/ControllerGenerator.php @@ -138,6 +138,15 @@ private function renderMethod(OperationDescriptor $operation): string $doc[] = ' *'; $doc[] = ' * '.$this->docblockSafe($operation->summary); } + if ($operation->deprecated) { + // The spec marks the operation `deprecated: true`. Emit a plain + // `@deprecated` tag, symmetric with the tag a deprecated schema + // gives its generated Data class (SchemaFacts::deprecationTag). + // OpenAPI's operation `deprecated` is a bare boolean with no reason + // field, so there is no text to attach. + $doc[] = ' *'; + $doc[] = ' * @deprecated'; + } if ($operation->queryParam !== null && ! $operation->queryParam['injected']) { // The query class is NOT injected here, for one of two reasons: the // request body occupies the payload and container resolution would diff --git a/src/Emitter/Server/OperationCollector.php b/src/Emitter/Server/OperationCollector.php index 36d916f..43117d7 100644 --- a/src/Emitter/Server/OperationCollector.php +++ b/src/Emitter/Server/OperationCollector.php @@ -419,6 +419,7 @@ private function describe(string $path, string $method, OperationNode $operation returnType: $returnType, returnDoc: $returnDoc, summary: $this->summary($operation), + deprecated: $operation->deprecated === true, imports: $imports, queryParam: $queryParam, pathDataParam: $pathDataParam, diff --git a/src/Emitter/Server/OperationDescriptor.php b/src/Emitter/Server/OperationDescriptor.php index 64f6278..71bcf81 100644 --- a/src/Emitter/Server/OperationDescriptor.php +++ b/src/Emitter/Server/OperationDescriptor.php @@ -61,6 +61,15 @@ public function __construct( public string $returnType, public ?string $returnDoc, public ?string $summary, + /* + * Whether the spec marks this operation `deprecated: true`. The + * abstract controller method carries an `@deprecated` docblock line + * when set, symmetric with the `@deprecated` tag a deprecated schema + * gives its generated Data class. OpenAPI's operation `deprecated` is a + * bare boolean with no reason field, so the line stays a plain + * `@deprecated`. + */ + public bool $deprecated, public array $imports, public ?array $queryParam = null, /* diff --git a/tests/Unit/Emitter/Server/DeprecatedOperationTest.php b/tests/Unit/Emitter/Server/DeprecatedOperationTest.php new file mode 100644 index 0000000..246f729 --- /dev/null +++ b/tests/Unit/Emitter/Server/DeprecatedOperationTest.php @@ -0,0 +1,81 @@ + abstract class name => generated code + */ +function generateDeprecatedOperationControllers(): array +{ + $document = [ + 'openapi' => '3.0.3', + 'info' => ['title' => 'Test', 'version' => '1.0.0'], + 'paths' => [ + '/legacy' => [ + 'get' => [ + 'tags' => ['Thing'], + 'operationId' => 'getLegacy', + 'summary' => 'A retired endpoint.', + 'deprecated' => true, + 'responses' => ['204' => ['description' => 'No content']], + ], + ], + '/current' => [ + 'get' => [ + 'tags' => ['Thing'], + 'operationId' => 'getCurrent', + 'summary' => 'A live endpoint.', + 'responses' => ['204' => ['description' => 'No content']], + ], + ], + ], + ]; + + $spec = (new OpenApiReader)->read($document); + expect($spec)->toBeInstanceOf(OpenApiDocument::class); + + $generator = new ModelGenerator; + $generator->generate($spec); + $options = new ServerOptions; + + $descriptors = (new OperationCollector($options, $generator->registry(), null, $generator))->collect($spec); + $files = (new ControllerGenerator($options))->generate($descriptors); + + return array_map(fn ($file) => $file->code, $files); +} + +it('emits an @deprecated docblock on the method of a deprecated operation', function () { + $code = generateDeprecatedOperationControllers()['AbstractThingController']; + + // The deprecated operation's method carries the tag. + expect($code)->toContain(' * @deprecated') + ->and($code)->toContain('public function getLegacy('); + + // It rides in the same docblock as the summary, not as loose text. + $deprecatedMethod = substr($code, (int) strpos($code, 'A retired endpoint.'), 200); + expect($deprecatedMethod)->toContain('@deprecated'); +}); + +it('does not emit @deprecated on a non-deprecated operation', function () { + $code = generateDeprecatedOperationControllers()['AbstractThingController']; + + // Only one @deprecated line across the whole controller: the legacy method. + expect(substr_count($code, '@deprecated'))->toBe(1); + + // The live method's docblock (between its summary and its signature) has none. + $liveStart = (int) strpos($code, 'A live endpoint.'); + $liveBlock = substr($code, $liveStart, (int) strpos($code, 'public function getCurrent(') - $liveStart); + expect($liveBlock)->not->toContain('@deprecated'); +}); From 84e225b58af4ede37f32e592babab9d700433ca5 Mon Sep 17 00:00:00 2001 From: benjamineckstein <13351939+benjamineckstein@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:57:03 +0200 Subject: [PATCH 2/2] test(corpus): rebaseline 22 specs for deprecated controller docblocks --- tests/Corpus/ReaderCorpusBaselineTest.php | 62 +++++++++++++++++++-- tests/Fixtures/corpus-baseline-v0.11.0.json | 44 +++++++-------- 2 files changed, 79 insertions(+), 27 deletions(-) diff --git a/tests/Corpus/ReaderCorpusBaselineTest.php b/tests/Corpus/ReaderCorpusBaselineTest.php index cbfbe37..386aea7 100644 --- a/tests/Corpus/ReaderCorpusBaselineTest.php +++ b/tests/Corpus/ReaderCorpusBaselineTest.php @@ -1227,6 +1227,58 @@ 'zuora.json' => 'final query Data factory return type changed from static to self', ]; +/* + * INTENTIONAL post-freeze rebaseline (deprecated controller docblocks): the 22 + * specs in READER_BASELINE_REBASELINED_DEPRECATED_CONTROLLER_DOCBLOCKS carry a + * post-fix hash because they declare at least one operation marked + * `deprecated: true`, whose abstract controller method now carries an + * `@deprecated` docblock line (symmetric with the `@deprecated` tag a + * deprecated schema already gives its generated Data class). OpenAPI's + * operation `deprecated` is a bare boolean with no reason field, so the line is + * a plain `@deprecated`. The ONLY divergence in each of these hashes is the + * added `@deprecated` docblock line(s) on the affected abstract controller + * methods: a strict, additive documentation improvement, no existing file + * dropped, retyped, or reworded, and the warning lists are byte-identical. A + * spec also present in an earlier rebaseline list accumulates the change; every + * spec outside the rebaseline lists stays the frozen v0.11.0 freeze, byte for + * byte. + */ + +/** + * Specs whose frozen hash was deliberately updated to the post-fix output (a + * deprecated operation's abstract controller method gains an `@deprecated` + * docblock line), keyed by spec basename. The per-spec test below still + * compares against the JSON baseline, which now holds these specs' post-fix + * hashes; the coverage test pins that every listed name exists on disk and in + * the baseline, so the list cannot rot. + * + * @var array + */ +const READER_BASELINE_REBASELINED_DEPRECATED_CONTROLLER_DOCBLOCKS = [ + 'adyen-checkout.yaml' => 'deprecated operation gains an @deprecated controller method docblock', + 'apple_appstore.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'aws_lambda.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'aws_s3.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'bitbucket.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'codat_accounting.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'codat_banking.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'digitalocean.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'dracoon.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'elevenlabs.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'github.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'here_tracking.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'jira.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'linode.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'openai.yaml' => 'deprecated operation gains an @deprecated controller method docblock', + 'plaid.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'resend.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'shutterstock.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'soundcloud.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'spotify.yaml' => 'deprecated operation gains an @deprecated controller method docblock', + 'stripe.json' => 'deprecated operation gains an @deprecated controller method docblock', + 'zoom.json' => 'deprecated operation gains an @deprecated controller method docblock', +]; + /** * Corpus specs added AFTER the v0.11.0 baseline freeze (#104 T8: the OpenAPI * 3.2 fixtures). The frozen baseline cannot contain them by definition, so @@ -1297,11 +1349,11 @@ // Every spec rebaselined for #110, #116, #120, #122, #124, #125, #126, // #113, #121, #129, #30, #130, the transitive nested-readOnly write split, - // #132 (delimited arrays), or #131 (deepObject object query parameters) - // must still exist on disk and carry a hash in the baseline (it is an - // update, not an exemption): a renamed or deleted spec would make the - // documented rebaseline lists rot silently. - foreach ([...array_keys(READER_BASELINE_REBASELINED_110), ...array_keys(READER_BASELINE_REBASELINED_116), ...array_keys(READER_BASELINE_REBASELINED_120), ...array_keys(READER_BASELINE_REBASELINED_122), ...array_keys(READER_BASELINE_REBASELINED_124), ...array_keys(READER_BASELINE_REBASELINED_125), ...array_keys(READER_BASELINE_REBASELINED_126), ...array_keys(READER_BASELINE_REBASELINED_113), ...array_keys(READER_BASELINE_REBASELINED_121), ...array_keys(READER_BASELINE_REBASELINED_129), ...array_keys(READER_BASELINE_REBASELINED_129_INLINE_RESPONSES), ...array_keys(READER_BASELINE_REBASELINED_30), ...array_keys(READER_BASELINE_REBASELINED_NESTED_READONLY), ...array_keys(READER_BASELINE_REBASELINED_130), ...array_keys(READER_BASELINE_REBASELINED_DELIMITED_ARRAYS), ...array_keys(READER_BASELINE_REBASELINED_DEEPOBJECT), ...array_keys(READER_BASELINE_REBASELINED_SELF_STATIC)] as $spec) { + // #132 (delimited arrays), #131 (deepObject object query parameters), or the + // deprecated controller docblocks must still exist on disk and carry a hash + // in the baseline (it is an update, not an exemption): a renamed or deleted + // spec would make the documented rebaseline lists rot silently. + foreach ([...array_keys(READER_BASELINE_REBASELINED_110), ...array_keys(READER_BASELINE_REBASELINED_116), ...array_keys(READER_BASELINE_REBASELINED_120), ...array_keys(READER_BASELINE_REBASELINED_122), ...array_keys(READER_BASELINE_REBASELINED_124), ...array_keys(READER_BASELINE_REBASELINED_125), ...array_keys(READER_BASELINE_REBASELINED_126), ...array_keys(READER_BASELINE_REBASELINED_113), ...array_keys(READER_BASELINE_REBASELINED_121), ...array_keys(READER_BASELINE_REBASELINED_129), ...array_keys(READER_BASELINE_REBASELINED_129_INLINE_RESPONSES), ...array_keys(READER_BASELINE_REBASELINED_30), ...array_keys(READER_BASELINE_REBASELINED_NESTED_READONLY), ...array_keys(READER_BASELINE_REBASELINED_130), ...array_keys(READER_BASELINE_REBASELINED_DELIMITED_ARRAYS), ...array_keys(READER_BASELINE_REBASELINED_DEEPOBJECT), ...array_keys(READER_BASELINE_REBASELINED_SELF_STATIC), ...array_keys(READER_BASELINE_REBASELINED_DEPRECATED_CONTROLLER_DOCBLOCKS)] as $spec) { expect($specs)->toContain($spec) ->and($baseline)->toHaveKey($spec); } diff --git a/tests/Fixtures/corpus-baseline-v0.11.0.json b/tests/Fixtures/corpus-baseline-v0.11.0.json index 61f1ae1..35b8f43 100644 --- a/tests/Fixtures/corpus-baseline-v0.11.0.json +++ b/tests/Fixtures/corpus-baseline-v0.11.0.json @@ -2,12 +2,12 @@ "1password-connect.yaml": "2e94f4817462244d0c39b03d1254fdb9e4d6a1c53d4a3f2e8b9282ec98b0ca24", "ably.json": "fdd437d15b02ff6ea45200bf6b12b411f0b756f3992a8c99255c8cd1e9a9a8e0", "ably_control.json": "389e2bef69aaa0bdac774d7a0e4f9b14bdf22ddd0ec2228e7d75767f44322bae", - "adyen-checkout.yaml": "5d067a728f48fbe1e9a16a4209aae9c24a6c40fb868eb8fab5b55fcfa0443e44", + "adyen-checkout.yaml": "962f8b416c1689178d303b1b942f2eae6940b63775b438215b15fd0766e6baa6", "adyen-legal-entity.yaml": "c52a0c211ee769562815c7aa318a3cfed2a1fb3292cb62de9c5962e0cc55b42b", "airflow.json": "e52f6ee128478579eeccc92dd70f04d39f0474e53a6172daa065b5abf430776f", "amadeus.json": "1cf56ea89ec735b45a76a13710b03a534a822de4a95a43d14d9eee2d2a4bb739", "apisguru.json": "2d5125564c7dd85dd59dce9daff022f11430a54ea3dae5112c4378885513ec12", - "apple_appstore.json": "be51cc0c53259070e529abd99174654013114471969789676e69ef37962c0290", + "apple_appstore.json": "5e09ad705c889a0544743e9df34658e4988873dccd8bf8ed898d6a99be4058c2", "appwrite.json": "2a03b49af2d9ad66de076a2e764c37fd411cf2ce7932e19c663bdebea80fb52a", "asana.json": "b82dedabd07b440a0b8a04e576eac103460a3127c61b850f97f9b39738d4e92f", "aws_apigateway.json": "31558e8685a2dcb92823be8ba693836aaa7d248a49031cc2160e21acc01c10a9", @@ -15,16 +15,16 @@ "aws_cognito.json": "93faf457f56ef7ac6cc4fc9e093ae485eccf11628281c63c1c28a85f40f538cb", "aws_dynamodb.json": "730d67c16140c1e25c31823e5588cb9eaccf87f7e07d321af717f809323063ab", "aws_iam.json": "1ec58a51fa667c068bf27f72d90c46d62f2e89ea23e32ef3e05efe423e424076", - "aws_lambda.json": "99f7c2df59fce76e5bb7def6f02052fb68eaadab02dd1e45bdcb49f09aa46e7e", + "aws_lambda.json": "20613ea1b0c0ef17d04f69f1545179ecee228059659482766343e71434ae6d37", "aws_rds.json": "6acafc98f5efd3e5d400bf8d6dcb3343be23efe952e17add411fe7510a6477d4", - "aws_s3.json": "a1afa71742ead2cee480847f9d9bde4079f97dc064f551b11133a4f976afb3d9", + "aws_s3.json": "fe56a114cc6490370352b8028fe3386483d3a64057327c7b9c56f297ece49e3b", "aws_sns.json": "556eec616ba7e253c74241a9dfb9680860d40d6ba10d955337c44a31d249b9f0", "aws_sqs.json": "ba009fc3a36a1fd5d0bc8802629c860540a096dc6459940e5b5cd91f0c7cbc12", "balldontlie.json": "ee07d9eb6a3c5045b55200a0e00e1c2dc5b07a14c2a73bbb09620a8e3f11fb06", "bbc.json": "92605bca080fde343aa0fda8f76de083f6d364e00269b0a32c9113b3e4909b0d", "bigdatacloud.json": "1ff53b6e4d90cddb5ac0c44546a9368b9f4efad2fe8187e6c59435e1c2972280", "bikewise.json": "88a68146f94fbab440e43ac5f4d7e30c1c12eb49e6eb958aba22a718b7c58883", - "bitbucket.json": "b25f502b61c4450dd76866fddaffa9df70d2cbd23c14d5790f81fe82f53810d1", + "bitbucket.json": "18ac9242edf08f19c8b402e34ab1344b8034c1841b0f115cadadef86c575a041", "box.json": "bd87a42a79167d1a09a5160e59a9a41ed660355c94d5a0fdf36de958dc01fe55", "braze.json": "9a71106e801be815d034fa7a2686218b4c023f73e0729462f6378f6017e99d5f", "brex.json": "ce019d5650cf81474f3d84e37f2f2e12bbbfa4857577c35598fc8d4a2bb8a7b7", @@ -35,24 +35,24 @@ "clevercloud.json": "fd3cdcaecdb7124314e9db77f7fc4a5e374e1e34c7d78f77a3e011e8700c1115", "clicksend.json": "022584af297d9e08772f2b4e3ed626310be7654b71c03fa18de78b2d581da002", "clickup.json": "c01f2c4c2dd154f5a7d6728cc50312d484bdd746445e5511586e75f6115bd06b", - "codat_accounting.json": "a5eea7ead1c479d47e568e299d97e9d99e20a5247480228615241be9bfa5bf0f", - "codat_banking.json": "a9b78fc09e70bedbb9c3fb6a5006e8159026488016b9f55bc3c6ece934db28f4", + "codat_accounting.json": "d3b014c2962f4bee78b6093bd7270a0af5efea67f692bace6350dfe2e4572d7c", + "codat_banking.json": "135a03e6b91027eaf448ef686afcf8bc7d98df73dec5cd626c2d5bfddf264c61", "configcat.json": "774cacba14d178d27df9e38fad4aff4ee8c32ff04465c41a25f3dbba00fdf8b9", "devto.json": "4a163faa352050a402ce320d7cf8c5e8035055a9bc10c2f4de1ac021ff1e28f2", - "digitalocean.json": "450f9c4ebdec0fa2e64e0ff6b16bf379750dfaa446d8615a6c503c6f407d93dc", + "digitalocean.json": "7c83bea3c6d48ddeb3e835642dfb8b7f8c79979b0f468b6f6b348b2df8ca013c", "discourse.json": "006932c02117a0da0569b58caf30e285d5f47b7a54a93f0bc9ea7ce26d0b19d8", "dnd5e.json": "04e3a9752a4dd83e34d78b7e7153bf53c07ce63ce75146199538344d98677fd0", "docker.json": "cff74a4bec9ef5437cfe5260d9e3aea4ad95d7a17fb718ec99ec15692d1a2def", "docusign.json": "bef5e137645dfe04ef01d9ae1935cd406dbf08ac50dc59308f78bd13f669303d", - "dracoon.json": "adeff1f6a4e912d46f49d242f2810382442b2bf922d479e869c2506e2334e723", + "dracoon.json": "49c6cc80a70ec5946a69285fdfa2ebc0e508cc36764f9ab7850cf0809177d7be", "ebay_fulfillment.json": "c979b15a04f5afc2f0b489d37cbc9fd18615c548343bd612437eeee416287aec", "ebay_marketing.json": "bab14e060fa2fcb75e5b6572f719e5fd3d0c60f0b3a2c72f2c20b5e27031f05e", - "elevenlabs.json": "f6a128c3e5150951e271fe65403fb275954ca34c24f2e83f1b5a0d60ba4deece", + "elevenlabs.json": "7604c6ac2b766a704724e1f6d96a40765f301ad68793c1c3ac81bef7fea1187d", "exchangerate.json": "e423074045c279af42d2ca60eb2c0b9798dbab09f919c1768bafe1b0b2946674", "flickr.json": "a8330d212bbda6a1908cb17fa7ce3091fed97911ef169402a32813958ca2a530", "gettyimages.json": "ff2c3951367471a581d93aafb41baccb7e83dab5ccfbe3df5e0432ee2c50ba1d", "giphy.json": "6120256779160ccd6aff12bb6a1cec6c503c0b52a2f9e47f9a8d639badf59a72", - "github.json": "f4af358dbdaf541ea1bc6280c8696e262344877fc709d218489356607b4e6fd0", + "github.json": "c7b0c6a634e3891a780a9c56cab3f281e9d5fc87ca91fe7d1e2d2f0e9d49748a", "google_bigquery.json": "7087ef8a7a9a4e1573fd61a9350ff3cc23ab677019a06a6ec688959dcedfc726", "google_calendar.json": "87c0d1c7bbe79482671e9d9fb2b3e77a5329120782b000c8bd44d2ebb8aab9a6", "google_cloudrun.json": "3ea01eaec4230ebf2d4ef46ff06d0277bc0e845f0c2a30d0e6b4e867103576d4", @@ -71,11 +71,11 @@ "google_tts.json": "1ef896fbb7ab5e26485c76a896e3b3758f1addb3710e8f7112e0085dceffd7a8", "google_vision.json": "9eddae72e27dcbefb9cbe02f499b3405fa0ee0bd9d7a7e924cd58628c132660f", "here_positioning.json": "b29a6c283898d28760cd5bbe9199dfd15b152efcaeadca7d441a702c3f0fc35d", - "here_tracking.json": "a21e47f45b1fcba4dab092b8f312c5a6b62dda901b2021eb20e949d4c4635ce4", + "here_tracking.json": "d24c402762e253bdb1b331b358dafb754185b5827b8a76d48a49440a391041a0", "ipgeo.json": "d79a7ed96c6cd6881230b44d2756ce1a6d2df9073a27996254d32acdfa479606", - "jira.json": "882fddec848dfc8b273e0709a0b795a1001a6aa8b84a0a0c1771a19b21c95703", + "jira.json": "eb8016da1bca2bb005daa7a16d7ed47b5189421f49f22e6ffe5f19a6a5945679", "klarna.json": "a74ccb35b288bad37a4a8de2bc9e2d3820a5c0424088fbe2fac1a173110ed646", - "linode.json": "362e0c2c3f67c5693ade995a6eea9def104931d276f6ae0b320f1daf62717d41", + "linode.json": "a805736d2e72338fae40fe2ba950504cb936855873420a39ab67fdf36ee0f4d9", "lufthansa.json": "d8c2ebd03fef485a35d6ca7f8fdfd019ca104f835ec63dc2521c0e2a8a502afa", "medium.json": "d883a4fcc7a4016d90611a62198dfc6a7e5e1067ac59c753d686af93798ae808", "nasa_apod.json": "b4728b33c5a22ffe802fea0daf52c0753245a3bd353106b15958fc0d623fc110", @@ -83,27 +83,27 @@ "nytimes.json": "58f971f50a4a0cb0e21459f746d3331d1d8d3a2df200e67bd63c254d1e090d61", "okta.json": "ac9e57f511299e667b562c0807dfe3ba5662e44549881c68edf7f6a9eae9c618", "open-meteo.yaml": "1dd2676fa2a0c8edec659bef4280bfa1f651189463f5ecd777a6b07a55266dda", - "openai.yaml": "1804ae5114e92bb6b2c2e9b02eee12d600ef2d81db6f08c78528a175eec24f03", + "openai.yaml": "d9c3dbb6cc57c1d2df8fc1d1d318561a037744dee828f5bdb75b63daef141f17", "openbanking.json": "1ab49e7f2e2d1238bea630e131f1d6a29585708b290a43283c5215a33aee8a0f", "petstore-3.0.yaml": "5549b8f0be75ce713336a3c5dbebda3a3f425a0cc79a433606045fe96d4fec4c", "pinecone.json": "cce266037cc62a05c92e6ab16bb7f04caf6357ff3bf9a2de7abe0c60347049d2", - "plaid.json": "fdd8ac2fe9ec2615394db84639b786ab32e2fb6ad901489397414f38df7b6c95", + "plaid.json": "92e1dd06a27d4b57ccd92a7daaf3afc17594c2aaf93f153fd7ee7130f7d14acc", "postman.json": "3877c442064b415ddfea4cec7f43994087e6f8eee5cc953fb7ee1068db7a7fad", "rawg.json": "4537a738188b73041319c546d0e045172d0af58ebb554e60c45ff4b04030019c", "redocly-museum.yaml": "117c9d904d27cc7a30db0cc870d89374ff3b3f5f306fd6115dbe84d214b6dac6", - "resend.json": "35e40d996dcb26a6d8e3defdc85dcd3dfa0c500c043befd95861d0aaf5454f35", + "resend.json": "02b69917b76a9a911d3dd654e00d90e09160d5416747ad436831ddec638b847e", "reverb.json": "4149c338ed85f31da02cb31ffda07017f90432ce14d97f64c8fc0b1ec86df19a", "sendgrid.json": "d03b5b4a43bacac922fc7ef2e9321ccbbc6bb4eb9667ed8e9e85af96dd1100a7", "sentry.json": "c9a106f431a0e015e87265176309b066469f97844e3680433bcf7da2bd3ef77d", "shipstation.json": "c01f2c4c2dd154f5a7d6728cc50312d484bdd746445e5511586e75f6115bd06b", - "shutterstock.json": "f4679da0451c3f874eec2d05dbbd84767cc72573d93690ef13c598deb589ac2f", + "shutterstock.json": "ce0d39eafb228a796e9b9760730bde2b19598e364b6a5d84793815f4c7131db3", "slack.json": "fb719293ae1d339aed0c6a8abc4f4250492565ed56f379f4799b41172f993866", "snyk.json": "ff7630502d18ef3110635488b56d9ab40f4028c912c9cd3106e6383b1ae8cf9c", - "soundcloud.json": "75f3ed7e37d3fb7954f597cf7cc3a7b67535a2eff778297e0dc2aca21095cda1", - "spotify.yaml": "f976882cab9e9d9c293e208dc42ffa2a5fe988d61da98830eab480963856d73c", + "soundcloud.json": "213eaec519f2970983070dab0e45baa6f14fa0055653b2fcabdf32e4243e8b02", + "spotify.yaml": "5dba5c819228d5f3a51e21d32d21fd6879b3146677b6897f6b29898a72853dff", "square.json": "6200e620d4707053b2076ece569c3c161ccdba07ceb403b7e3815f69b1b83a15", "stackexchange.json": "23c70bdcd2ba7b77bc285b6a0d590b2e78ca2cc68f4059cf81d42c34df5acde8", - "stripe.json": "f421dec38870761d6c78d3f0595162c4243f07067c22def86fa7c58009daf0f7", + "stripe.json": "68dda0b2216b24f07a951fbfaa955b3affaf1fa4510f31698bbdf1a38600c666", "telegram.json": "27c8e76a1257e47be6b37880bd9e76a40179e2dbb484657a61448d42d319830e", "tomtom_maps.json": "df79a71bee66086c1962011cb0c0f31bed551f8d622abe8541931b8debeeefdc", "tomtom_routing.json": "c1b4b1c1f8f0fbdf7382b7cbcbd23432cf90abec889a8323d60c188fe6eacab2", @@ -127,6 +127,6 @@ "xero.json": "7488788caef5e5bfdc9597f34cab944eceb3d03112c5c14c6c43599031b1b421", "xero_assets.json": "5a2ee47426d950ccf3d556ce303fca8d9db8d1f29bee6344788d941851ec5455", "youtube.json": "24e2618cb16e13d5cd553713bef34a74f786abe290156f9705a792ddabee10fe", - "zoom.json": "00b19820a29bc2c1e01108a940ef4421f7ccc3e975d89bed81f3682ef805f945", + "zoom.json": "8bb7e3e9b0463323d2d75bb58f953e647f17608237c30fcad9a843006eb35f43", "zuora.json": "16e546dc1145fedb33639506595d484102227dac9ad4f8dd1f2442a3c6454320" }