From 9304370fdb17a7b37e94231fc558c5c9ace95f02 Mon Sep 17 00:00:00 2001 From: benjamineckstein <13351939+benjamineckstein@users.noreply.github.com> Date: Sat, 13 Jun 2026 19:53:36 +0200 Subject: [PATCH 1/4] fix(emitter): emit self:: instead of static:: return type in final generated Data factories The fromQuery/fromRoute/fromHeaders factory methods on the per-operation query/path/header Data classes declared a ': static' return type. Those classes are always emitted final, so 'static' is redundant (QDPHP PhpUnnecessaryStaticReferenceInspection); 'self' is the correct, equivalent declaration. Regenerated the petstore and writable examples and updated the server-scaffold snapshot so the drift gates stay byte-identical. --- .../petstore/Data/Pet/DeletePetHeaderData.php | 2 +- .../petstore/Data/Pet/DeletePetPathData.php | 2 +- .../Data/Pet/FindPetsByStatusQueryData.php | 2 +- .../Data/Pet/FindPetsByTagsQueryData.php | 2 +- .../petstore/Data/Pet/GetPetByIdPathData.php | 2 +- .../Data/Pet/UpdatePetWithFormPathData.php | 2 +- .../Data/Pet/UpdatePetWithFormQueryData.php | 2 +- .../petstore/Data/Pet/UploadFilePathData.php | 2 +- .../petstore/Data/Pet/UploadFileQueryData.php | 2 +- .../Data/Store/DeleteOrderPathData.php | 2 +- .../Data/Store/GetOrderByIdPathData.php | 2 +- .../petstore/Data/User/DeleteUserPathData.php | 2 +- .../Data/User/GetUserByNamePathData.php | 2 +- .../petstore/Data/User/LoginUserQueryData.php | 2 +- .../petstore/Data/User/UpdateUserPathData.php | 2 +- src/Emitter/ClassRenderer.php | 12 ++++---- ...er_scaffold_snapshot_for_petstore_3_0.snap | 30 +++++++++---------- .../Data/Widgets/GetWidgetByIdPathData.php | 2 +- .../Emitter/Server/OperationCollectorTest.php | 2 +- 19 files changed, 38 insertions(+), 38 deletions(-) diff --git a/examples/petstore/Data/Pet/DeletePetHeaderData.php b/examples/petstore/Data/Pet/DeletePetHeaderData.php index 312f825..220c103 100644 --- a/examples/petstore/Data/Pet/DeletePetHeaderData.php +++ b/examples/petstore/Data/Pet/DeletePetHeaderData.php @@ -25,7 +25,7 @@ public function __construct( * lowercased) and each value is an array, so the first value of each * declared header is taken before validation. */ - public static function fromHeaders(Request $request): static + public static function fromHeaders(Request $request): self { $all = $request->headers->all(); $headers = []; diff --git a/examples/petstore/Data/Pet/DeletePetPathData.php b/examples/petstore/Data/Pet/DeletePetPathData.php index c2008c4..3675f76 100644 --- a/examples/petstore/Data/Pet/DeletePetPathData.php +++ b/examples/petstore/Data/Pet/DeletePetPathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/examples/petstore/Data/Pet/FindPetsByStatusQueryData.php b/examples/petstore/Data/Pet/FindPetsByStatusQueryData.php index ebc8e8d..bf8b311 100644 --- a/examples/petstore/Data/Pet/FindPetsByStatusQueryData.php +++ b/examples/petstore/Data/Pet/FindPetsByStatusQueryData.php @@ -21,7 +21,7 @@ public function __construct( * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } diff --git a/examples/petstore/Data/Pet/FindPetsByTagsQueryData.php b/examples/petstore/Data/Pet/FindPetsByTagsQueryData.php index f6ca2bb..d3c2928 100644 --- a/examples/petstore/Data/Pet/FindPetsByTagsQueryData.php +++ b/examples/petstore/Data/Pet/FindPetsByTagsQueryData.php @@ -21,7 +21,7 @@ public function __construct( * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } diff --git a/examples/petstore/Data/Pet/GetPetByIdPathData.php b/examples/petstore/Data/Pet/GetPetByIdPathData.php index cc47c79..58cafe7 100644 --- a/examples/petstore/Data/Pet/GetPetByIdPathData.php +++ b/examples/petstore/Data/Pet/GetPetByIdPathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/examples/petstore/Data/Pet/UpdatePetWithFormPathData.php b/examples/petstore/Data/Pet/UpdatePetWithFormPathData.php index ac85b45..0c20322 100644 --- a/examples/petstore/Data/Pet/UpdatePetWithFormPathData.php +++ b/examples/petstore/Data/Pet/UpdatePetWithFormPathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/examples/petstore/Data/Pet/UpdatePetWithFormQueryData.php b/examples/petstore/Data/Pet/UpdatePetWithFormQueryData.php index 9b1b00e..3959d08 100644 --- a/examples/petstore/Data/Pet/UpdatePetWithFormQueryData.php +++ b/examples/petstore/Data/Pet/UpdatePetWithFormQueryData.php @@ -21,7 +21,7 @@ public function __construct( * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } diff --git a/examples/petstore/Data/Pet/UploadFilePathData.php b/examples/petstore/Data/Pet/UploadFilePathData.php index 78c2aac..26fae1d 100644 --- a/examples/petstore/Data/Pet/UploadFilePathData.php +++ b/examples/petstore/Data/Pet/UploadFilePathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/examples/petstore/Data/Pet/UploadFileQueryData.php b/examples/petstore/Data/Pet/UploadFileQueryData.php index 9f2a027..66d8565 100644 --- a/examples/petstore/Data/Pet/UploadFileQueryData.php +++ b/examples/petstore/Data/Pet/UploadFileQueryData.php @@ -20,7 +20,7 @@ public function __construct( * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } diff --git a/examples/petstore/Data/Store/DeleteOrderPathData.php b/examples/petstore/Data/Store/DeleteOrderPathData.php index 0b5be2d..3c84929 100644 --- a/examples/petstore/Data/Store/DeleteOrderPathData.php +++ b/examples/petstore/Data/Store/DeleteOrderPathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/examples/petstore/Data/Store/GetOrderByIdPathData.php b/examples/petstore/Data/Store/GetOrderByIdPathData.php index b80599c..23ab8b4 100644 --- a/examples/petstore/Data/Store/GetOrderByIdPathData.php +++ b/examples/petstore/Data/Store/GetOrderByIdPathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/examples/petstore/Data/User/DeleteUserPathData.php b/examples/petstore/Data/User/DeleteUserPathData.php index db1ebec..55dcee8 100644 --- a/examples/petstore/Data/User/DeleteUserPathData.php +++ b/examples/petstore/Data/User/DeleteUserPathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/examples/petstore/Data/User/GetUserByNamePathData.php b/examples/petstore/Data/User/GetUserByNamePathData.php index 9806898..f50886c 100644 --- a/examples/petstore/Data/User/GetUserByNamePathData.php +++ b/examples/petstore/Data/User/GetUserByNamePathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/examples/petstore/Data/User/LoginUserQueryData.php b/examples/petstore/Data/User/LoginUserQueryData.php index b2d86de..7376a4e 100644 --- a/examples/petstore/Data/User/LoginUserQueryData.php +++ b/examples/petstore/Data/User/LoginUserQueryData.php @@ -21,7 +21,7 @@ public function __construct( * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } diff --git a/examples/petstore/Data/User/UpdateUserPathData.php b/examples/petstore/Data/User/UpdateUserPathData.php index 9bb659f..887560c 100644 --- a/examples/petstore/Data/User/UpdateUserPathData.php +++ b/examples/petstore/Data/User/UpdateUserPathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/src/Emitter/ClassRenderer.php b/src/Emitter/ClassRenderer.php index 0f03b18..ff80c1b 100644 --- a/src/Emitter/ClassRenderer.php +++ b/src/Emitter/ClassRenderer.php @@ -453,7 +453,7 @@ private function renderFromQuery(array $booleanNames, array $delimitedArrays = [ if ($booleanNames === [] && $delimitedArrays === []) { return $doc .' */'."\n" - .' public static function fromQuery(Request $request): static'."\n" + .' public static function fromQuery(Request $request): self'."\n" ." {\n" .' return self::validateAndCreate($request->query->all());'."\n" .' }'; @@ -504,7 +504,7 @@ private function renderFromQuery(array $booleanNames, array $delimitedArrays = [ return $doc .$docExtra .' */'."\n" - .' public static function fromQuery(Request $request): static'."\n" + .' public static function fromQuery(Request $request): self'."\n" ." {\n" .$body ."\n" @@ -540,7 +540,7 @@ private function renderFromRoute(array $booleanNames): string if ($booleanNames === []) { return $doc .' */'."\n" - .' public static function fromRoute(Request $request): static'."\n" + .' public static function fromRoute(Request $request): self'."\n" ." {\n" .' return self::validateAndCreate($request->route()->parameters());'."\n" .' }'; @@ -555,7 +555,7 @@ private function renderFromRoute(array $booleanNames): string .' * Boolean parameters arrive as the form-style literals true / false,'."\n" .' * which are mapped to 1 / 0 before validation.'."\n" .' */'."\n" - .' public static function fromRoute(Request $request): static'."\n" + .' public static function fromRoute(Request $request): self'."\n" ." {\n" .' $parameters = $request->route()->parameters();'."\n" ."\n" @@ -622,7 +622,7 @@ private function renderFromHeaders(array $headerNames, array $booleanNames): str if ($booleanNames === []) { return $doc .' */'."\n" - .' public static function fromHeaders(Request $request): static'."\n" + .' public static function fromHeaders(Request $request): self'."\n" ." {\n" .$prologue ."\n" @@ -639,7 +639,7 @@ private function renderFromHeaders(array $headerNames, array $booleanNames): str .' * Boolean parameters arrive as the form-style literals true / false,'."\n" .' * which are mapped to 1 / 0 before validation.'."\n" .' */'."\n" - .' public static function fromHeaders(Request $request): static'."\n" + .' public static function fromHeaders(Request $request): self'."\n" ." {\n" .$prologue ."\n" diff --git a/tests/.pest/snapshots/Unit/Emitter/Server/ServerScaffoldSnapshotTest/it_matches_the_committed_server_scaffold_snapshot_for_petstore_3_0.snap b/tests/.pest/snapshots/Unit/Emitter/Server/ServerScaffoldSnapshotTest/it_matches_the_committed_server_scaffold_snapshot_for_petstore_3_0.snap index de17dfc..0419bc2 100644 --- a/tests/.pest/snapshots/Unit/Emitter/Server/ServerScaffoldSnapshotTest/it_matches_the_committed_server_scaffold_snapshot_for_petstore_3_0.snap +++ b/tests/.pest/snapshots/Unit/Emitter/Server/ServerScaffoldSnapshotTest/it_matches_the_committed_server_scaffold_snapshot_for_petstore_3_0.snap @@ -235,7 +235,7 @@ final class FindPetsByStatusQueryData extends Data * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } @@ -274,7 +274,7 @@ final class FindPetsByTagsQueryData extends Data * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } @@ -314,7 +314,7 @@ final class LoginUserQueryData extends Data * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } @@ -354,7 +354,7 @@ final class UpdatePetWithFormQueryData extends Data * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } @@ -393,7 +393,7 @@ final class UploadFileQueryData extends Data * Validate against rules() and hydrate from the query string only, so * request-body fields never bleed into query validation (or vice versa). */ - public static function fromQuery(Request $request): static + public static function fromQuery(Request $request): self { return self::validateAndCreate($request->query->all()); } @@ -432,7 +432,7 @@ final class DeleteOrderPathData extends Data * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } @@ -471,7 +471,7 @@ final class DeletePetPathData extends Data * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } @@ -510,7 +510,7 @@ final class DeleteUserPathData extends Data * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } @@ -549,7 +549,7 @@ final class GetOrderByIdPathData extends Data * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } @@ -588,7 +588,7 @@ final class GetPetByIdPathData extends Data * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } @@ -627,7 +627,7 @@ final class GetUserByNamePathData extends Data * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } @@ -666,7 +666,7 @@ final class UpdatePetWithFormPathData extends Data * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } @@ -705,7 +705,7 @@ final class UpdateUserPathData extends Data * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } @@ -744,7 +744,7 @@ final class UploadFilePathData extends Data * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } @@ -787,7 +787,7 @@ final class DeletePetHeaderData extends Data * lowercased) and each value is an array, so the first value of each * declared header is taken before validation. */ - public static function fromHeaders(Request $request): static + public static function fromHeaders(Request $request): self { $all = $request->headers->all(); $headers = []; diff --git a/tests/Feature/Example/Writable/Data/Widgets/GetWidgetByIdPathData.php b/tests/Feature/Example/Writable/Data/Widgets/GetWidgetByIdPathData.php index bd296da..37dc284 100644 --- a/tests/Feature/Example/Writable/Data/Widgets/GetWidgetByIdPathData.php +++ b/tests/Feature/Example/Writable/Data/Widgets/GetWidgetByIdPathData.php @@ -21,7 +21,7 @@ public function __construct( * only, so path-segment constraints are enforced at runtime (a bad value * is a 422, not a silent 200). */ - public static function fromRoute(Request $request): static + public static function fromRoute(Request $request): self { return self::validateAndCreate($request->route()->parameters()); } diff --git a/tests/Unit/Emitter/Server/OperationCollectorTest.php b/tests/Unit/Emitter/Server/OperationCollectorTest.php index c0c8b8e..a2e5823 100644 --- a/tests/Unit/Emitter/Server/OperationCollectorTest.php +++ b/tests/Unit/Emitter/Server/OperationCollectorTest.php @@ -602,7 +602,7 @@ function collectWithHeaderClasses(): array ->and($code)->toContain("'ids.*' => ['integer', 'min:1']") ->and($code)->toContain("'q' => ['sometimes', 'string', 'max:64', 'min:2']") // Every query class carries the query-only factory. - ->and($code)->toContain('public static function fromQuery(Request $request): static') + ->and($code)->toContain('public static function fromQuery(Request $request): self') ->and($code)->toContain('return self::validateAndCreate($request->query->all());'); }); From cfced97bb8219085aec778bdd248f3ff0bd31c80 Mon Sep 17 00:00:00 2001 From: benjamineckstein <13351939+benjamineckstein@users.noreply.github.com> Date: Sat, 13 Jun 2026 19:57:40 +0200 Subject: [PATCH 2/4] refactor: clear mechanical QDPHP source findings - OperationCollector: convert the three component-map accumulate-with-if loops (parameters, requestBodies, responses) to array_filter with ARRAY_FILTER_USE_BOTH (PhpLoopCanBeConvertedToArrayFilter); PHPStan max still narrows the value type from the instanceof in each callback. - CommandRequestFactory: inline the single-caller configMiddlewareMap key (PhpSameParameterValue) and rewrite the resolveBoolean ternary as '$configured === null || (bool) $configured' (PhpTernaryExpressionCanBeReplacedWithCondition). - RequestDataSynthesizer: complete generateParamData's PHPDoc to cover every parameter and the return (PhpDocSignatureIsNotComplete). - EnumEmitter: mark the class final readonly; its only property is the promoted readonly GenerationState (PhpClassCanBeReadonly). --- src/Console/CommandRequestFactory.php | 8 ++--- src/Emitter/EnumEmitter.php | 4 +-- src/Emitter/RequestDataSynthesizer.php | 8 +++-- src/Emitter/Server/OperationCollector.php | 39 +++++++++-------------- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/Console/CommandRequestFactory.php b/src/Console/CommandRequestFactory.php index 6c1b7f4..4999f7b 100644 --- a/src/Console/CommandRequestFactory.php +++ b/src/Console/CommandRequestFactory.php @@ -94,7 +94,7 @@ public function fromCommand(Command $command, bool $stubs = false): GenerationRe // Security-to-middleware mapping (issue #77). Config-only like the // route group settings: a map is config-shaped, there is no CLI flag. - $securityMiddlewareMap = $this->configMiddlewareMap('openapi-laravel.security.middleware_map'); + $securityMiddlewareMap = $this->configMiddlewareMap(); return new GenerationRequest( $spec, @@ -132,9 +132,9 @@ public function fromCommand(Command $command, bool $stubs = false): GenerationRe * * @return array> */ - private function configMiddlewareMap(string $key): array + private function configMiddlewareMap(): array { - $configured = config($key); + $configured = config('openapi-laravel.security.middleware_map'); if (! is_array($configured)) { return []; } @@ -332,7 +332,7 @@ private function resolveToggle(Command $command, string $flag, string $configKey $configured = config($configKey); - return $configured === null ? true : (bool) $configured; + return $configured === null || (bool) $configured; } private function stringOption(Command $command, string $name): ?string diff --git a/src/Emitter/EnumEmitter.php b/src/Emitter/EnumEmitter.php index 446c2ef..06acbf4 100644 --- a/src/Emitter/EnumEmitter.php +++ b/src/Emitter/EnumEmitter.php @@ -17,10 +17,10 @@ * * @internal */ -final class EnumEmitter +final readonly class EnumEmitter { public function __construct( - private readonly GenerationState $state, + private GenerationState $state, ) {} public function emitEnum(string $className, SchemaNode $schema): void diff --git a/src/Emitter/RequestDataSynthesizer.php b/src/Emitter/RequestDataSynthesizer.php index 642146d..dc11bdc 100644 --- a/src/Emitter/RequestDataSynthesizer.php +++ b/src/Emitter/RequestDataSynthesizer.php @@ -208,8 +208,12 @@ public function generateHeaderData(string $baseName, string $operationLabel, arr * presence-only `mixed`, and header additionally skips the reserved * framework-owned standard headers. * - * @param 'query'|'path'|'header' $in - * @param list $parameters + * @param 'query'|'path'|'header' $in the parameter location this call synthesizes a class for + * @param string $baseName StudlyCaps operation context (operationId or the method+path fallback), without suffix + * @param string $operationLabel "GET /pets", for warning messages + * @param list $parameters the operation's parameters; only those matching `$in` are kept + * @param ?string $tag the operation's first tag (or the 'Untagged' fallback) for the grouped layout (issue #93); ignored in the flat layout + * @return string|null the synthesized class name, or null when every parameter was skipped */ private function generateParamData(string $in, string $baseName, string $operationLabel, array $parameters, ?string $tag): ?string { diff --git a/src/Emitter/Server/OperationCollector.php b/src/Emitter/Server/OperationCollector.php index 0db4687..36d916f 100644 --- a/src/Emitter/Server/OperationCollector.php +++ b/src/Emitter/Server/OperationCollector.php @@ -967,14 +967,11 @@ private function componentParameters(OpenApiDocument $document): array return []; } - $result = []; - foreach ($components->parameters as $name => $parameter) { - if (is_string($name) && $name !== '' && $parameter instanceof ParameterNode) { - $result[$name] = $parameter; - } - } - - return $result; + return array_filter( + $components->parameters, + static fn (mixed $parameter, mixed $name): bool => is_string($name) && $name !== '' && $parameter instanceof ParameterNode, + ARRAY_FILTER_USE_BOTH, + ); } /** @@ -993,14 +990,11 @@ private function collectComponentRequestBodies(OpenApiDocument $document): array return []; } - $result = []; - foreach ($components->requestBodies as $name => $body) { - if (is_string($name) && $name !== '' && $body instanceof RequestBodyNode) { - $result[$name] = $body; - } - } - - return $result; + return array_filter( + $components->requestBodies, + static fn (mixed $body, mixed $name): bool => is_string($name) && $name !== '' && $body instanceof RequestBodyNode, + ARRAY_FILTER_USE_BOTH, + ); } /** @@ -1086,14 +1080,11 @@ private function collectComponentResponses(OpenApiDocument $document): array return []; } - $result = []; - foreach ($components->responses as $name => $response) { - if (is_string($name) && $name !== '' && $response instanceof ResponseNode) { - $result[$name] = $response; - } - } - - return $result; + return array_filter( + $components->responses, + static fn (mixed $response, mixed $name): bool => is_string($name) && $name !== '' && $response instanceof ResponseNode, + ARRAY_FILTER_USE_BOTH, + ); } /** From 3e40ea746377e6b892b7ee34969737ee68554cfa Mon Sep 17 00:00:00 2001 From: benjamineckstein <13351939+benjamineckstein@users.noreply.github.com> Date: Sat, 13 Jun 2026 19:57:51 +0200 Subject: [PATCH 3/4] ci(qodana): suppress four false-positive inspection classes - PhpUnnecessaryStringCast: the remaining '(string) ...' casts are load-bearing (numeric-string array-key coercion guard, and collapsing json_encode's string|false return for sprintf %s), the same rationale as the already-disabled PhpCastIsUnnecessaryInspection. - PhpSameParameterValue (scoped to the two CLI files): repeatedOption and resolveRepeatable are deliberate general-purpose argv/config helpers, not dead generality. - PhpInternalEntityUsed (scoped to bin/openapi-laravel): the bin script is the package's own framework-free entrypoint and the legitimate consumer of the @internal StandaloneApplication (#69: the whole PHP class API is internal; the supported surface is the CLI and artisan command). - PhpCoverageInspection: the Clover report fed to Qodana (#89) comes from the fast suite only, so lines exercised solely by the slow corpus gate show as uncovered noise; full line coverage is enforced by composer test:type. --- qodana.yaml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/qodana.yaml b/qodana.yaml index e5f4452..a8ef816 100644 --- a/qodana.yaml +++ b/qodana.yaml @@ -51,3 +51,40 @@ exclude: # and couple two otherwise self-contained rules, which breaks the inlining # story. The duplication is the price of keeping each rule self-contained. - name: DuplicatedCode + # The remaining `(string) ...` casts the emitter keeps are load-bearing, not + # redundant: `(string) $name` restores the string-key invariant after PHP + # coerces a numeric-string array key (e.g. "200") to int at runtime (the same + # rationale as PhpCastIsUnnecessaryInspection above), and + # `(string) json_encode(...)` collapses json_encode's `string|false` return to + # a string so the `%s` sprintf argument is well-typed. Both guard real + # behaviour, so this inspection is a false positive here. + - name: PhpUnnecessaryStringCast + # PhpSameParameterValue fires on the framework-free CLI's general-purpose + # helpers `repeatedOption()` (StandaloneApplication) and `resolveRepeatable()` + # (CommandRequestFactory). Each is a deliberate, named, reusable seam (parse a + # repeatable --flag from argv; resolve a repeatable flag against its config + # key); they happen to have a single repeatable flag today. Inlining the flag + # name would couple a generic parser to one option and hurt readability, so + # the seam is intentional, not dead generality. + - name: PhpSameParameterValue + paths: + - src/Console/StandaloneApplication.php + - src/Console/CommandRequestFactory.php + # bin/openapi-laravel is the package's own framework-free entry point and the + # legitimate first-party consumer of StandaloneApplication. The class is + # @internal by design (#69: the whole PHP class API is internal; the supported + # interface is the CLI and the artisan command, not direct class use), so the + # bin script using it is correct, not a violation. + - name: PhpInternalEntityUsed + paths: + - bin/openapi-laravel + # The Clover report fed to Qodana (#89) comes from the FAST suite only + # (--exclude-group=slow), so the slow corpus gate (ReaderCorpusBaselineTest + # runs the parser/emitter over all 135 specs) never contributes coverage to + # the report. The lines that gate alone exercises then show up as + # "uncovered" in Qodana even though the full `composer test` run hits them + # and the dedicated 100% line-coverage gate (`composer test:type`) enforces + # them. Running the full slow suite under coverage in this informational + # workflow would roughly triple its runtime for no signal we do not already + # have, so this inspection is pure noise here. + - name: PhpCoverageInspection From 1bcf9932c16884364c9cedcda1a4e98cfba063b7 Mon Sep 17 00:00:00 2001 From: benjamineckstein <13351939+benjamineckstein@users.noreply.github.com> Date: Sat, 13 Jun 2026 20:05:42 +0200 Subject: [PATCH 4/4] test(corpus): rebaseline 116 specs for the self:: query factory return type The self:: instead of static:: emitter fix changes one token on every generated fromQuery() signature, so 116 corpus specs diverge from the frozen v0.11.0 baseline. This is an intentional, auditable post-freeze rebaseline: add READER_BASELINE_REBASELINED_SELF_STATIC documenting every affected spec, refresh exactly those hashes in corpus-baseline-v0.11.0.json (key order and format preserved, the 5 post-freeze 3.2 specs untouched), and pin the new list in the coverage test so it cannot rot. Every spec outside the rebaseline lists stays the frozen freeze, byte for byte. --- tests/Corpus/ReaderCorpusBaselineTest.php | 135 +++++++++++- tests/Fixtures/corpus-baseline-v0.11.0.json | 232 ++++++++++---------- 2 files changed, 250 insertions(+), 117 deletions(-) diff --git a/tests/Corpus/ReaderCorpusBaselineTest.php b/tests/Corpus/ReaderCorpusBaselineTest.php index 7e8765f..cbfbe37 100644 --- a/tests/Corpus/ReaderCorpusBaselineTest.php +++ b/tests/Corpus/ReaderCorpusBaselineTest.php @@ -1094,6 +1094,139 @@ 'stripe.json' => 'deepObject object query parameters synthesized as nested query classes', ]; +/* + * INTENTIONAL post-freeze rebaseline (QDPHP self-vs-static sweep): the 116 + * specs in READER_BASELINE_REBASELINED_SELF_STATIC carry a refreshed hash + * because the per-operation query Data factory's return type changed from + * `: static` to `: self`. The classes are always emitted final, so static + * was redundant there (Qodana PhpUnnecessaryStaticReferenceInspection); self + * is the equivalent, non-redundant declaration. The divergence is exactly + * that one-token change on each generated fromQuery() (and, off the baseline + * pipeline, fromRoute()/fromHeaders()) signature, nothing else. A spec 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. + * + * @var array + */ +const READER_BASELINE_REBASELINED_SELF_STATIC = [ + '1password-connect.yaml' => 'final query Data factory return type changed from static to self', + 'ably.json' => 'final query Data factory return type changed from static to self', + 'adyen-checkout.yaml' => 'final query Data factory return type changed from static to self', + 'adyen-legal-entity.yaml' => 'final query Data factory return type changed from static to self', + 'airflow.json' => 'final query Data factory return type changed from static to self', + 'amadeus.json' => 'final query Data factory return type changed from static to self', + 'apple_appstore.json' => 'final query Data factory return type changed from static to self', + 'appwrite.json' => 'final query Data factory return type changed from static to self', + 'asana.json' => 'final query Data factory return type changed from static to self', + 'aws_apigateway.json' => 'final query Data factory return type changed from static to self', + 'aws_cloudformation.json' => 'final query Data factory return type changed from static to self', + 'aws_cognito.json' => 'final query Data factory return type changed from static to self', + 'aws_dynamodb.json' => 'final query Data factory return type changed from static to self', + 'aws_iam.json' => 'final query Data factory return type changed from static to self', + 'aws_lambda.json' => 'final query Data factory return type changed from static to self', + 'aws_rds.json' => 'final query Data factory return type changed from static to self', + 'aws_s3.json' => 'final query Data factory return type changed from static to self', + 'aws_sns.json' => 'final query Data factory return type changed from static to self', + 'aws_sqs.json' => 'final query Data factory return type changed from static to self', + 'balldontlie.json' => 'final query Data factory return type changed from static to self', + 'bbc.json' => 'final query Data factory return type changed from static to self', + 'bigdatacloud.json' => 'final query Data factory return type changed from static to self', + 'bikewise.json' => 'final query Data factory return type changed from static to self', + 'bitbucket.json' => 'final query Data factory return type changed from static to self', + 'box.json' => 'final query Data factory return type changed from static to self', + 'braze.json' => 'final query Data factory return type changed from static to self', + 'brex.json' => 'final query Data factory return type changed from static to self', + 'bungie.json' => 'final query Data factory return type changed from static to self', + 'canada_holidays.json' => 'final query Data factory return type changed from static to self', + 'circleci.json' => 'final query Data factory return type changed from static to self', + 'clevercloud.json' => 'final query Data factory return type changed from static to self', + 'codat_accounting.json' => 'final query Data factory return type changed from static to self', + 'codat_banking.json' => 'final query Data factory return type changed from static to self', + 'configcat.json' => 'final query Data factory return type changed from static to self', + 'devto.json' => 'final query Data factory return type changed from static to self', + 'digitalocean.json' => 'final query Data factory return type changed from static to self', + 'discourse.json' => 'final query Data factory return type changed from static to self', + 'dnd5e.json' => 'final query Data factory return type changed from static to self', + 'docker.json' => 'final query Data factory return type changed from static to self', + 'docusign.json' => 'final query Data factory return type changed from static to self', + 'dracoon.json' => 'final query Data factory return type changed from static to self', + 'ebay_fulfillment.json' => 'final query Data factory return type changed from static to self', + 'ebay_marketing.json' => 'final query Data factory return type changed from static to self', + 'elevenlabs.json' => 'final query Data factory return type changed from static to self', + 'flickr.json' => 'final query Data factory return type changed from static to self', + 'gettyimages.json' => 'final query Data factory return type changed from static to self', + 'giphy.json' => 'final query Data factory return type changed from static to self', + 'github.json' => 'final query Data factory return type changed from static to self', + 'google_bigquery.json' => 'final query Data factory return type changed from static to self', + 'google_calendar.json' => 'final query Data factory return type changed from static to self', + 'google_cloudrun.json' => 'final query Data factory return type changed from static to self', + 'google_compute.json' => 'final query Data factory return type changed from static to self', + 'google_docs.json' => 'final query Data factory return type changed from static to self', + 'google_drive.json' => 'final query Data factory return type changed from static to self', + 'google_functions.json' => 'final query Data factory return type changed from static to self', + 'google_gke.json' => 'final query Data factory return type changed from static to self', + 'google_gmail.json' => 'final query Data factory return type changed from static to self', + 'google_logging.json' => 'final query Data factory return type changed from static to self', + 'google_monitoring.json' => 'final query Data factory return type changed from static to self', + 'google_pubsub.json' => 'final query Data factory return type changed from static to self', + 'google_sheets.json' => 'final query Data factory return type changed from static to self', + 'google_speech.json' => 'final query Data factory return type changed from static to self', + 'google_translate.json' => 'final query Data factory return type changed from static to self', + 'google_tts.json' => 'final query Data factory return type changed from static to self', + 'google_vision.json' => 'final query Data factory return type changed from static to self', + 'here_positioning.json' => 'final query Data factory return type changed from static to self', + 'here_tracking.json' => 'final query Data factory return type changed from static to self', + 'ipgeo.json' => 'final query Data factory return type changed from static to self', + 'jira.json' => 'final query Data factory return type changed from static to self', + 'linode.json' => 'final query Data factory return type changed from static to self', + 'lufthansa.json' => 'final query Data factory return type changed from static to self', + 'medium.json' => 'final query Data factory return type changed from static to self', + 'nasa_apod.json' => 'final query Data factory return type changed from static to self', + 'notion.json' => 'final query Data factory return type changed from static to self', + 'nytimes.json' => 'final query Data factory return type changed from static to self', + 'okta.json' => 'final query Data factory return type changed from static to self', + 'open-meteo.yaml' => 'final query Data factory return type changed from static to self', + 'openai.yaml' => 'final query Data factory return type changed from static to self', + 'petstore-3.0.yaml' => 'final query Data factory return type changed from static to self', + 'postman.json' => 'final query Data factory return type changed from static to self', + 'rawg.json' => 'final query Data factory return type changed from static to self', + 'redocly-museum.yaml' => 'final query Data factory return type changed from static to self', + 'resend.json' => 'final query Data factory return type changed from static to self', + 'reverb.json' => 'final query Data factory return type changed from static to self', + 'sendgrid.json' => 'final query Data factory return type changed from static to self', + 'sentry.json' => 'final query Data factory return type changed from static to self', + 'shutterstock.json' => 'final query Data factory return type changed from static to self', + 'slack.json' => 'final query Data factory return type changed from static to self', + 'snyk.json' => 'final query Data factory return type changed from static to self', + 'soundcloud.json' => 'final query Data factory return type changed from static to self', + 'spotify.yaml' => 'final query Data factory return type changed from static to self', + 'square.json' => 'final query Data factory return type changed from static to self', + 'stackexchange.json' => 'final query Data factory return type changed from static to self', + 'stripe.json' => 'final query Data factory return type changed from static to self', + 'tomtom_maps.json' => 'final query Data factory return type changed from static to self', + 'tomtom_routing.json' => 'final query Data factory return type changed from static to self', + 'traccar.json' => 'final query Data factory return type changed from static to self', + 'trello.json' => 'final query Data factory return type changed from static to self', + 'twilio.json' => 'final query Data factory return type changed from static to self', + 'twilio_api_v2010.json' => 'final query Data factory return type changed from static to self', + 'twilio_messaging.json' => 'final query Data factory return type changed from static to self', + 'twilio_verify.json' => 'final query Data factory return type changed from static to self', + 'twilio_video.json' => 'final query Data factory return type changed from static to self', + 'twitter.json' => 'final query Data factory return type changed from static to self', + 'vercel.json' => 'final query Data factory return type changed from static to self', + 'vimeo.json' => 'final query Data factory return type changed from static to self', + 'wayback.json' => 'final query Data factory return type changed from static to self', + 'weather_visual.json' => 'final query Data factory return type changed from static to self', + 'webflow.json' => 'final query Data factory return type changed from static to self', + 'wolfram.json' => 'final query Data factory return type changed from static to self', + 'wordnik.json' => 'final query Data factory return type changed from static to self', + 'xero.json' => 'final query Data factory return type changed from static to self', + 'xero_assets.json' => 'final query Data factory return type changed from static to self', + 'youtube.json' => 'final query Data factory return type changed from static to self', + 'zoom.json' => 'final query Data factory return type changed from static to self', + 'zuora.json' => 'final query Data factory return type changed from static to self', +]; + /** * 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 @@ -1168,7 +1301,7 @@ // 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)] as $spec) { + 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) { 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 5295e04..61f1ae1 100644 --- a/tests/Fixtures/corpus-baseline-v0.11.0.json +++ b/tests/Fixtures/corpus-baseline-v0.11.0.json @@ -1,132 +1,132 @@ { - "1password-connect.yaml": "acf8d150213c5ed6a66bab0e59a674a6cd5ad0c12943649fd1ccc500de36f7e2", - "ably.json": "5fafadeb31601c8ef7f748c2af814b4721800cfb20cbe50e63f6c2037069d173", + "1password-connect.yaml": "2e94f4817462244d0c39b03d1254fdb9e4d6a1c53d4a3f2e8b9282ec98b0ca24", + "ably.json": "fdd437d15b02ff6ea45200bf6b12b411f0b756f3992a8c99255c8cd1e9a9a8e0", "ably_control.json": "389e2bef69aaa0bdac774d7a0e4f9b14bdf22ddd0ec2228e7d75767f44322bae", - "adyen-checkout.yaml": "b818450b292b17660bfeb46669e358a975c645295555bb4cfc2e12b50086c89f", - "adyen-legal-entity.yaml": "1c5f1371c875a93ab4fd3f7dc96fd7cdb871aeb80d6cd3b5636dcfaee88a742d", - "airflow.json": "db2d18c27117de0ca4c564d29410b25c24e7ec56946a8c9b32097e6c4b0e7471", - "amadeus.json": "ce418ef8a6088ff81b97277c63404b84d981ba7db80b38a007ebf250c8b9aefb", + "adyen-checkout.yaml": "5d067a728f48fbe1e9a16a4209aae9c24a6c40fb868eb8fab5b55fcfa0443e44", + "adyen-legal-entity.yaml": "c52a0c211ee769562815c7aa318a3cfed2a1fb3292cb62de9c5962e0cc55b42b", + "airflow.json": "e52f6ee128478579eeccc92dd70f04d39f0474e53a6172daa065b5abf430776f", + "amadeus.json": "1cf56ea89ec735b45a76a13710b03a534a822de4a95a43d14d9eee2d2a4bb739", "apisguru.json": "2d5125564c7dd85dd59dce9daff022f11430a54ea3dae5112c4378885513ec12", - "apple_appstore.json": "5a6695e13da08f5383629af205519130f030b9dffba3e17eaf62823e24d948a3", - "appwrite.json": "99a9bf3eefe499bd2a704da43e73aba00c0513de5b5a398a437bc39a5e446524", - "asana.json": "4707ff78b13c4866e42456533effb4569e7b8598979b4e70c3a31f7c521a9e53", - "aws_apigateway.json": "2ecb586ed1fe8e8bfc3cd87ceb678b742d5689ce8ba79f7e2c7aecc3521bf28f", - "aws_cloudformation.json": "43998c940a46ee9606829f65d1897ef96d4a021d284ce3cf45c1cfad8b5d3799", - "aws_cognito.json": "8666ebc31874eff4d00fcc422cb65c350b808490390645ff107091378e1fa351", - "aws_dynamodb.json": "8f12571ebc1a93ec96672390734d2b665bdc2c91d53063d52aa03b3edb5664ec", - "aws_iam.json": "73c38447e9237015da4df204c285f498910dd5ebf0fd7f60a381ff93ef1c4a9f", - "aws_lambda.json": "f90a5238a27fe2a7ebacc4ab6664b3b1c014582d715da038eee9a814aeb9308e", - "aws_rds.json": "11213cc16d11fc915436735f71d3c3d0a6334b97f7117bd6a8a3529b7c9b02c9", - "aws_s3.json": "ef76a15c07ce63ea955dc54fe7248a4e0758505828bc87c306814aafb237ed52", - "aws_sns.json": "335eae7145c496709cf8c4d5d1107afa0f050a5a7efd066b54bd3b70fe65af42", - "aws_sqs.json": "02516da2b57da68dffe846fe3cbf690cba060a40b91376242af8cf9244cb4355", - "balldontlie.json": "f66023c3655aa2e956864d0c23a1ea4c9164916e3b9c100057ce38df0dd765f6", - "bbc.json": "b8d442a7b58aca0947ca741ee549b843bbcc20809588e3831ad4a1f2bb492636", - "bigdatacloud.json": "5b1785b932e2562e13d5062ef1c0af3f2c5b4aa44efea35889eedd0fcee70d18", - "bikewise.json": "11edd1e463c59ed9892d55dd50efee0fdbf7ef65c0298aba8ff9840aa3902614", - "bitbucket.json": "559f880c0f06c01215cee739da897a21cc0163fe11bd78739aa255020a2b5ed7", - "box.json": "9999e0280a7a0affb395dde97f60fd0c2384d2c0b03cdcdef87ce9d169d1c2a8", - "braze.json": "eadfd34ab12226f1bd941c9d917c2abc761e981e2b7fdc98ace2ad4fc60520ad", - "brex.json": "e3028a38bc68156c277386c3d442d8e98d10e537bddb29fb27f1c2582fe89eee", - "bungie.json": "63ffdbb89f9cecd89a47badb433c0af45d14d94e9cf7e59d31c9bdac0f6855b6", + "apple_appstore.json": "be51cc0c53259070e529abd99174654013114471969789676e69ef37962c0290", + "appwrite.json": "2a03b49af2d9ad66de076a2e764c37fd411cf2ce7932e19c663bdebea80fb52a", + "asana.json": "b82dedabd07b440a0b8a04e576eac103460a3127c61b850f97f9b39738d4e92f", + "aws_apigateway.json": "31558e8685a2dcb92823be8ba693836aaa7d248a49031cc2160e21acc01c10a9", + "aws_cloudformation.json": "2384b16b8e267f56a11dc5985bb4b235a58ed08d254e78833b87921f9d2ff739", + "aws_cognito.json": "93faf457f56ef7ac6cc4fc9e093ae485eccf11628281c63c1c28a85f40f538cb", + "aws_dynamodb.json": "730d67c16140c1e25c31823e5588cb9eaccf87f7e07d321af717f809323063ab", + "aws_iam.json": "1ec58a51fa667c068bf27f72d90c46d62f2e89ea23e32ef3e05efe423e424076", + "aws_lambda.json": "99f7c2df59fce76e5bb7def6f02052fb68eaadab02dd1e45bdcb49f09aa46e7e", + "aws_rds.json": "6acafc98f5efd3e5d400bf8d6dcb3343be23efe952e17add411fe7510a6477d4", + "aws_s3.json": "a1afa71742ead2cee480847f9d9bde4079f97dc064f551b11133a4f976afb3d9", + "aws_sns.json": "556eec616ba7e253c74241a9dfb9680860d40d6ba10d955337c44a31d249b9f0", + "aws_sqs.json": "ba009fc3a36a1fd5d0bc8802629c860540a096dc6459940e5b5cd91f0c7cbc12", + "balldontlie.json": "ee07d9eb6a3c5045b55200a0e00e1c2dc5b07a14c2a73bbb09620a8e3f11fb06", + "bbc.json": "92605bca080fde343aa0fda8f76de083f6d364e00269b0a32c9113b3e4909b0d", + "bigdatacloud.json": "1ff53b6e4d90cddb5ac0c44546a9368b9f4efad2fe8187e6c59435e1c2972280", + "bikewise.json": "88a68146f94fbab440e43ac5f4d7e30c1c12eb49e6eb958aba22a718b7c58883", + "bitbucket.json": "b25f502b61c4450dd76866fddaffa9df70d2cbd23c14d5790f81fe82f53810d1", + "box.json": "bd87a42a79167d1a09a5160e59a9a41ed660355c94d5a0fdf36de958dc01fe55", + "braze.json": "9a71106e801be815d034fa7a2686218b4c023f73e0729462f6378f6017e99d5f", + "brex.json": "ce019d5650cf81474f3d84e37f2f2e12bbbfa4857577c35598fc8d4a2bb8a7b7", + "bungie.json": "13bdfd0eac2af4eb332012a8e03e8781000d531a974d217c602c3e893e3461b9", "bunq.json": "506c94276360af38310f805ae58ba6995a09f02bffbb0430e95c6b7d1376403b", - "canada_holidays.json": "3c2da8ec81a9ba47ea9c22db31b35ec1fdbff7391b77b828c6f7888cf22c398d", - "circleci.json": "5312d1e48c572059b179ae2f1ad23150a3e3fb5023ef205a45591194e8f99eed", - "clevercloud.json": "11ff98bcf5d1f71d285cbe1743629f24866fb097999a28da867628600645b706", + "canada_holidays.json": "34c19b08c0a20ece1fce8c623dacea3548190ed238215a8e09d188ff48b55cad", + "circleci.json": "051c29d94f930115240785553d591475646d46af7ce05be04fb804e6de3288f5", + "clevercloud.json": "fd3cdcaecdb7124314e9db77f7fc4a5e374e1e34c7d78f77a3e011e8700c1115", "clicksend.json": "022584af297d9e08772f2b4e3ed626310be7654b71c03fa18de78b2d581da002", "clickup.json": "c01f2c4c2dd154f5a7d6728cc50312d484bdd746445e5511586e75f6115bd06b", - "codat_accounting.json": "a894b286f7aed9f6ae6b933f41f4b6298f3156d4efb8799076f61a821a91ca76", - "codat_banking.json": "b10f0199d67468ba0dfa3fc7c0aa3486e90c0f2dc6c0022027da03ae9e366901", - "configcat.json": "f3afe52241b09e0f039ed94703eaaa8849bbeb3cdd4edacb92eb0e8139f49a05", - "devto.json": "1dfd78e6e130537c0ec2e90e9738bc56ee2e14469cb7f0f1efffaeb734e81eb1", - "digitalocean.json": "74e3efaebb1ac9e39276b8ef439b5292ad88d9e0f686898c51877ace2e706153", - "discourse.json": "ca1da3caff154612e4de779045dc334b18b7fda12d0e0e64d44e2f79c731552d", - "dnd5e.json": "07d2b56a7575c678f824eb937afe11524e6e3073fd535ac8f11a572aab55e09c", - "docker.json": "81fb9338d64c2de343bec3647a536100f233cfe720f6f28283ab899aabf2c06f", - "docusign.json": "8e69a8064d4f06b950f79795eb3d3229aacb119a5ac52c16236af8361c1eb4de", - "dracoon.json": "6f6ffd22b2073b963a01ec5d9a1b7ed39459ab059cdc2c4a5e75d18ddb1fda98", - "ebay_fulfillment.json": "7e85f687a3654be68230571cb7ca0463ba7e489ed3e164b9601dc3fd9966a63e", - "ebay_marketing.json": "ae6446ac3d65a53127cf1ce50d5159734799dd5d0515d162c4d684c054c3e62f", - "elevenlabs.json": "882bb29c1f4094ad546274ad3aaeed9d0c8bddf817a5de7dcc3bd47a2ff21085", + "codat_accounting.json": "a5eea7ead1c479d47e568e299d97e9d99e20a5247480228615241be9bfa5bf0f", + "codat_banking.json": "a9b78fc09e70bedbb9c3fb6a5006e8159026488016b9f55bc3c6ece934db28f4", + "configcat.json": "774cacba14d178d27df9e38fad4aff4ee8c32ff04465c41a25f3dbba00fdf8b9", + "devto.json": "4a163faa352050a402ce320d7cf8c5e8035055a9bc10c2f4de1ac021ff1e28f2", + "digitalocean.json": "450f9c4ebdec0fa2e64e0ff6b16bf379750dfaa446d8615a6c503c6f407d93dc", + "discourse.json": "006932c02117a0da0569b58caf30e285d5f47b7a54a93f0bc9ea7ce26d0b19d8", + "dnd5e.json": "04e3a9752a4dd83e34d78b7e7153bf53c07ce63ce75146199538344d98677fd0", + "docker.json": "cff74a4bec9ef5437cfe5260d9e3aea4ad95d7a17fb718ec99ec15692d1a2def", + "docusign.json": "bef5e137645dfe04ef01d9ae1935cd406dbf08ac50dc59308f78bd13f669303d", + "dracoon.json": "adeff1f6a4e912d46f49d242f2810382442b2bf922d479e869c2506e2334e723", + "ebay_fulfillment.json": "c979b15a04f5afc2f0b489d37cbc9fd18615c548343bd612437eeee416287aec", + "ebay_marketing.json": "bab14e060fa2fcb75e5b6572f719e5fd3d0c60f0b3a2c72f2c20b5e27031f05e", + "elevenlabs.json": "f6a128c3e5150951e271fe65403fb275954ca34c24f2e83f1b5a0d60ba4deece", "exchangerate.json": "e423074045c279af42d2ca60eb2c0b9798dbab09f919c1768bafe1b0b2946674", - "flickr.json": "787072f0834f60251934c003427b9f58ab05b0228bd80b552a902751c5f3045f", - "gettyimages.json": "355ad6299b3944d91bd236d5f3b1c49166285d6f7df128164d063bd52c02783d", - "giphy.json": "6cfc142f0306d9fc1b77afaac7dc6706b773370b4330c5e2bde5119d5e47889f", - "github.json": "d70719c042ad9f8b458b69d3c535d4fdee0ffed5207622eed5bb4607378dd6a1", - "google_bigquery.json": "d312b219894089afad83291b82a0794a4a62403b79b1e7c962e375e1459cbb2c", - "google_calendar.json": "3cd499dedac3e23dc534387aa31e3d208353ce0a4b6ac831929201450f943d45", - "google_cloudrun.json": "ba2954b5ad8162bf7265cc5bd0eefc2cf5275209a2ffd42d6083094abdc8c843", - "google_compute.json": "1e8d054f0060e3f11bfe67c25fcc8f6893777cc8a2d84b1d61c866c2af8c7815", - "google_docs.json": "7a9d419f1f695874d7691ca396c7ceacf3da9bff43b809472dd950a4a336a575", - "google_drive.json": "dc6ef7766a54044700350a371d9a80befc898d41023a77dfa85ee50d9ad1b416", - "google_functions.json": "bc1f0050eb00cfd3039ef63d6c69880e20b2b6825f1208f060db405ff5c1a3e0", - "google_gke.json": "4cbe35b8beb950bf695e3cff50a6c781c9cbd231e3fa7a39509a50c57b5bbced", - "google_gmail.json": "21862206ff545c5936f039889e008c2f274e497383ccb98a093037ebcbd61985", - "google_logging.json": "16752d8ca59614f8c7e36667d8896d1ebca6918d403f0ada16b751213f4e936f", - "google_monitoring.json": "dd7dea3003f6f294138a8471be112f11ed9081f0a8e8198b898912454b5392c4", - "google_pubsub.json": "0aaf087f9a576f6c19ccdbbc89ca96ed556515880d1266da74cdea2e9baeedc7", - "google_sheets.json": "6de09de042570184b20bb7dc3a8c64905e8dc52b99421a4dca2e409edf390a72", - "google_speech.json": "4967a79a44dd375c70de2dcb12249a76d44b46fedfaf5c959ad5077e163b4c7d", - "google_translate.json": "1d9fbe8730e18569b217406d3431c262cae7189143044c288f1cb503b40c0aed", - "google_tts.json": "9c67860e574af8ef15f2d0b8db63cc496a34f76d03d568643a042bd5ff9bceda", - "google_vision.json": "04071abdc6e9922d799983ecacab8c2bc236f7ed19ff846dfe36689f0b8f3c67", - "here_positioning.json": "950eaca008e7341e4dd8b92575c6965dbdffe8ddd4babf4fe53be39f17629798", - "here_tracking.json": "e260fc1b370e2f130ef7f8b9f873a972babe9b63dd4a9db0a51bf64a2516db6d", - "ipgeo.json": "ef75ef622deadb513067c7578b2153169c2f7b246cb9c7b736879d6b19bd1d6f", - "jira.json": "dd01b593e307d24c6748c3443f529fcf1f6ac9e78c6e625f7256249e5d39949d", + "flickr.json": "a8330d212bbda6a1908cb17fa7ce3091fed97911ef169402a32813958ca2a530", + "gettyimages.json": "ff2c3951367471a581d93aafb41baccb7e83dab5ccfbe3df5e0432ee2c50ba1d", + "giphy.json": "6120256779160ccd6aff12bb6a1cec6c503c0b52a2f9e47f9a8d639badf59a72", + "github.json": "f4af358dbdaf541ea1bc6280c8696e262344877fc709d218489356607b4e6fd0", + "google_bigquery.json": "7087ef8a7a9a4e1573fd61a9350ff3cc23ab677019a06a6ec688959dcedfc726", + "google_calendar.json": "87c0d1c7bbe79482671e9d9fb2b3e77a5329120782b000c8bd44d2ebb8aab9a6", + "google_cloudrun.json": "3ea01eaec4230ebf2d4ef46ff06d0277bc0e845f0c2a30d0e6b4e867103576d4", + "google_compute.json": "6b281eeee0a5bb3a86de336a742323f0db07b4537c153f3a39f2b43708a76fe0", + "google_docs.json": "e98abb82f19ac0a34a1cb83ffebf600ea2019440b62cc1d6bea0ebd95a9382c0", + "google_drive.json": "9f0ecd4f924b3176f77cdfc4f45927502e20a0943952402d75223205f85f97f6", + "google_functions.json": "96e6624977b20fbf66447eded876625f7a752d3b26542f9961d0f08c28083fc5", + "google_gke.json": "5215c24eeb748bf2b095df9c3df419e2e4c84f615844216f2251160871ad5d1e", + "google_gmail.json": "88bd3e2bf99330a0db69518fa1fe4ea9779640681e37f20ee9c0f741ed16a8bc", + "google_logging.json": "88da29f8ea3f1e6dab07ae0ee4c6c99bccbe839531db0ef9d1e71f3c7d6af396", + "google_monitoring.json": "47ccca8fd62c1fd8fa87871d6b6d7f50b2338bcfcf84899f10faffd972f5f11c", + "google_pubsub.json": "b6880bb8c4be4ffca8ee2c42b8e934eb60fc51ecce423d71e0efa4b55e290000", + "google_sheets.json": "55f543bf99144f97d9e1f90a5f0f3c70d812fe67d6e2e71b4af3403dc6c7ccc3", + "google_speech.json": "678dba38df8ba9e6a881bcea7e574a68d72b555bffc4574356c52a28ab2032a9", + "google_translate.json": "268895a09e20d6ef0401c9137bc7c29abe059d9f7ca09a2622288492bf006c0b", + "google_tts.json": "1ef896fbb7ab5e26485c76a896e3b3758f1addb3710e8f7112e0085dceffd7a8", + "google_vision.json": "9eddae72e27dcbefb9cbe02f499b3405fa0ee0bd9d7a7e924cd58628c132660f", + "here_positioning.json": "b29a6c283898d28760cd5bbe9199dfd15b152efcaeadca7d441a702c3f0fc35d", + "here_tracking.json": "a21e47f45b1fcba4dab092b8f312c5a6b62dda901b2021eb20e949d4c4635ce4", + "ipgeo.json": "d79a7ed96c6cd6881230b44d2756ce1a6d2df9073a27996254d32acdfa479606", + "jira.json": "882fddec848dfc8b273e0709a0b795a1001a6aa8b84a0a0c1771a19b21c95703", "klarna.json": "a74ccb35b288bad37a4a8de2bc9e2d3820a5c0424088fbe2fac1a173110ed646", - "linode.json": "ab6555c56ae075dbd0f1cde2415b92ec14c740c8509f1ee1395d9b2a55529ea4", - "lufthansa.json": "3cedac44c42a86025e5d72b2b10c3f4affeaee57d71fa4aee465848dc38bb729", - "medium.json": "73e0529623f36626352ed08d77a28e2700eb4918f4dc2fbb7f8a98ee9f858503", - "nasa_apod.json": "fe053aa38ab8bcaed332851f7babcd3a90f7e617d23c52f7c671a6cf9013d274", - "notion.json": "add1c30f4e0b55c91660da2da6558697f4977928819cedf55d54827aa4b24703", - "nytimes.json": "01c6ef673e666b40d60b221d33f09cc47ec63bc1a4afca3f771f66fa366f3bb0", - "okta.json": "2c5a53b441c4e6adb75ac950ed30b2cacde10a28bf2f93604227a265bba8125f", - "open-meteo.yaml": "30ec2b4706786fb848ea2ee993079084ae8fe39c1457bd322accbe4ae60e7c49", - "openai.yaml": "a3ef37688785d20f259c9a42ba66c1e02770de3b0880e308826d53f72fd3c592", + "linode.json": "362e0c2c3f67c5693ade995a6eea9def104931d276f6ae0b320f1daf62717d41", + "lufthansa.json": "d8c2ebd03fef485a35d6ca7f8fdfd019ca104f835ec63dc2521c0e2a8a502afa", + "medium.json": "d883a4fcc7a4016d90611a62198dfc6a7e5e1067ac59c753d686af93798ae808", + "nasa_apod.json": "b4728b33c5a22ffe802fea0daf52c0753245a3bd353106b15958fc0d623fc110", + "notion.json": "1ef1052ef63099265332ad3a772a026f33c0ec75e5756f0877cf1399ff6eaf6b", + "nytimes.json": "58f971f50a4a0cb0e21459f746d3331d1d8d3a2df200e67bd63c254d1e090d61", + "okta.json": "ac9e57f511299e667b562c0807dfe3ba5662e44549881c68edf7f6a9eae9c618", + "open-meteo.yaml": "1dd2676fa2a0c8edec659bef4280bfa1f651189463f5ecd777a6b07a55266dda", + "openai.yaml": "1804ae5114e92bb6b2c2e9b02eee12d600ef2d81db6f08c78528a175eec24f03", "openbanking.json": "1ab49e7f2e2d1238bea630e131f1d6a29585708b290a43283c5215a33aee8a0f", - "petstore-3.0.yaml": "8fa36d0e89f4ddb0a520f18f6591714b08f96dee814d07da51812cb53a306143", + "petstore-3.0.yaml": "5549b8f0be75ce713336a3c5dbebda3a3f425a0cc79a433606045fe96d4fec4c", "pinecone.json": "cce266037cc62a05c92e6ab16bb7f04caf6357ff3bf9a2de7abe0c60347049d2", "plaid.json": "fdd8ac2fe9ec2615394db84639b786ab32e2fb6ad901489397414f38df7b6c95", - "postman.json": "f3fa83e36e4f80ab6067a2df003fbdc46516889b66bb40c3f2766672cbfff6da", - "rawg.json": "f6de5946dee9d4990be051ce5f0d4c90d1048df2c33e59749812ec40983db0a7", - "redocly-museum.yaml": "0fe99a6c9a865ed52428236309d130a7beaa86a037a19a2b0c3396b9ba67b5f4", - "resend.json": "e24f5648b20cc004adf347be274c384d97562078257d86079e758def3b754e14", - "reverb.json": "6a8e77e683bc7e043b05b4054c9215037211e5283a1da7706a4920523b98764f", - "sendgrid.json": "832914d3dc72176aa3df1b9be5a99d7d38f8bf6d29282fda139a551c1e03f8a3", - "sentry.json": "c8939710c4637d82c7a181aec52db0d81e009a6aa33345dc197f7c5604563058", + "postman.json": "3877c442064b415ddfea4cec7f43994087e6f8eee5cc953fb7ee1068db7a7fad", + "rawg.json": "4537a738188b73041319c546d0e045172d0af58ebb554e60c45ff4b04030019c", + "redocly-museum.yaml": "117c9d904d27cc7a30db0cc870d89374ff3b3f5f306fd6115dbe84d214b6dac6", + "resend.json": "35e40d996dcb26a6d8e3defdc85dcd3dfa0c500c043befd95861d0aaf5454f35", + "reverb.json": "4149c338ed85f31da02cb31ffda07017f90432ce14d97f64c8fc0b1ec86df19a", + "sendgrid.json": "d03b5b4a43bacac922fc7ef2e9321ccbbc6bb4eb9667ed8e9e85af96dd1100a7", + "sentry.json": "c9a106f431a0e015e87265176309b066469f97844e3680433bcf7da2bd3ef77d", "shipstation.json": "c01f2c4c2dd154f5a7d6728cc50312d484bdd746445e5511586e75f6115bd06b", - "shutterstock.json": "abb631473ca210f3806613829e2978e9bb6b92f93c09d4dae3f6a02e1ce25ec5", - "slack.json": "3ce29a42df540cb5ac6cc9b401abc8de2078dd9acbcca7009a905be5b4aed1b7", - "snyk.json": "f24dd8e79178ae647c011d4f6185b5cae61b8723c089e91bc5a00e9eedb61771", - "soundcloud.json": "acb118e283c1ee04b645f1aa1d32db2d52f5013ef85cc28aefee0a2fe9a06399", - "spotify.yaml": "c8901cc1ae5f51b82b53a626a7df24789ab8ca4df4d97c1fb0e5afff3995ac8c", - "square.json": "a236f574cbfebdde2732f6565ae3b6e9e060ae68ca0301ffc1dfcc40fe4b299f", - "stackexchange.json": "687dbd2be9c52dada45b09815698514aa75e631901b5f5f234da93a79d67cdba", - "stripe.json": "6b2d81ba5139cf82126805067fd4d7e0d0ddb2f1ab92392953ad87c20e1a39a3", + "shutterstock.json": "f4679da0451c3f874eec2d05dbbd84767cc72573d93690ef13c598deb589ac2f", + "slack.json": "fb719293ae1d339aed0c6a8abc4f4250492565ed56f379f4799b41172f993866", + "snyk.json": "ff7630502d18ef3110635488b56d9ab40f4028c912c9cd3106e6383b1ae8cf9c", + "soundcloud.json": "75f3ed7e37d3fb7954f597cf7cc3a7b67535a2eff778297e0dc2aca21095cda1", + "spotify.yaml": "f976882cab9e9d9c293e208dc42ffa2a5fe988d61da98830eab480963856d73c", + "square.json": "6200e620d4707053b2076ece569c3c161ccdba07ceb403b7e3815f69b1b83a15", + "stackexchange.json": "23c70bdcd2ba7b77bc285b6a0d590b2e78ca2cc68f4059cf81d42c34df5acde8", + "stripe.json": "f421dec38870761d6c78d3f0595162c4243f07067c22def86fa7c58009daf0f7", "telegram.json": "27c8e76a1257e47be6b37880bd9e76a40179e2dbb484657a61448d42d319830e", - "tomtom_maps.json": "487939235b13e5d80d3afae4856ee9b955805df05b55a37d353e2e7293b135d1", - "tomtom_routing.json": "2670c4881af1e3501dafb8f15e61530ebe6f987bab0c8f8b35679944254293a5", - "traccar.json": "c3f2e08aee8df5d77675cae83ee7c8e1b4d1560e82d16929162ded848dd1dbf1", - "trello.json": "aed12f1dce2e3334b2e05c6b6d40b305e2d78b2d2f2d6d003635803719fffbda", - "twilio.json": "589ed918e0c7e1e27c7fa6a831d7be768c382cbf3abf321e29db3435b1bd2685", - "twilio_api_v2010.json": "5c5128a26bc7a566e3b416b50de19e6fdbd9f0f40655343901a7c61bebea6bdf", - "twilio_messaging.json": "626d30a60a798e2ecd8a6ab3f9391285226e6a7428d0ecaa15dc7eb574a94603", - "twilio_verify.json": "eeb89a71df391c4bc55a6411d03f65c1f181b88720bde0d2ef72f137028a0c3b", - "twilio_video.json": "2cc4e4928a185f7168c7139740e8ddd0fa9648a4e7a626837fb9b01a229dc7dc", - "twitter.json": "2c7b32cb073198bd7a7690d410c19aaa045606d29ceac1c757c10b7aa75aa8df", - "vercel.json": "cef1db854144377f552f2cfc0a502ac19339a36361c5ffc76db92bbf68032305", - "vimeo.json": "57e5b19b10c35ee73f0cc157fd1cf942bef32db3c4d098fe98e0cbc3e204a26e", + "tomtom_maps.json": "df79a71bee66086c1962011cb0c0f31bed551f8d622abe8541931b8debeeefdc", + "tomtom_routing.json": "c1b4b1c1f8f0fbdf7382b7cbcbd23432cf90abec889a8323d60c188fe6eacab2", + "traccar.json": "cff9a618a137ccce4e58b293e83a5c9c7fc268a58b4f67414707d1797f69bb2f", + "trello.json": "cca6c834618ee3e4593741b476c172ff7fb48e742f7a84d4b9d02fb6ea61a27f", + "twilio.json": "3162f539de7231dc3fddeaf10a7800e5edfb39bb7bc61397e98f038bc4cd302e", + "twilio_api_v2010.json": "64db54ad40c6f316820bed31e3994acf05bab66445b9bb807e7bd88f6f330c42", + "twilio_messaging.json": "b56fbe96e5980883f80a8036996e922567a688f71778e813c2b4fe1ae1ca0405", + "twilio_verify.json": "b0190f14d2c0fb5adba552b91ea912bc4a7dd19277e34f944188c2bea40e4bac", + "twilio_video.json": "a7b06eccc8f45e878d938a3cafe3c053a6d9ef233976cbb29cc8766c206f6a1f", + "twitter.json": "5ef2117122616a2f50970c2bd1037d5f7a91aa1c43bd050c480b669242d207fe", + "vercel.json": "776dae0679d1e1fff44a605ec4098cf4d85ad0fc687dcf85a5931d4813f0f2e3", + "vimeo.json": "b7ff46ed87062c8afb54ac304fe9c85a3fbcc424a8da7692198cb8fb624f1fc3", "vonage.json": "2ff263de6d34fb15620810ecf4e203210e20c37ad5578787b052a82637494269", - "wayback.json": "a4a6c028649deca4fa87fb9d1495377df92b0f5c17e0059248ab31613a693ae8", - "weather_visual.json": "a69d4e9100afad00d52913b1c0e0927eb03e89de8ab6ade83b15d620f28311aa", - "webflow.json": "004704e6b63273f96bbd7e9cfb5e89fdd534a2af4cdbf56146cbcb1df6524816", - "wolfram.json": "c19fa10e488ad1bbbab89523f6dfd1eeccdf1d39cd7e5fa1f9a37650e7ec454a", - "wordnik.json": "ab74c718444fcd3644c5744922d3c4b80b2fbc6e7288c9553d361f3bc649c6e6", + "wayback.json": "a3f7c2a37022fd5471ac23bcabbc9605ee873752e94b518bc7b88a6243c1a045", + "weather_visual.json": "b822ba86865ab9145216dff6317cec2460f2037a7fd14116c796241ce1521357", + "webflow.json": "9197e0620ec572103dc3f5d933223095eb053139dcaa0c73bf92ab850e2adeef", + "wolfram.json": "2ae0df6603992293185e5cb898af2b523125cae632fd8cd08565870182f90aaa", + "wordnik.json": "4f3a6a907b8828239545b0cb5f74277f9a7114c2eb7211c69b0b7c52cee7ffcf", "worldtime.json": "9529fe0b1dd9137d8dcd00bc9f7bbc634999d14de9064ac64e35c45a4c2bfbc0", - "xero.json": "355220dc70511a6b097d560e09c799ac633cd7309e64b8de58801da5ed8913fc", - "xero_assets.json": "609e04e11f708248f822789643f6489adeed722deb7f3e1471eaf73b1bf92409", - "youtube.json": "e54498cec3caf8acc29dd3a08d295ca4e560936211c7548f97b8b17527bcf4f1", - "zoom.json": "485a7784475d958eb3a0efb20932882b4049a0be76850d5a2b48c4c754a17273", - "zuora.json": "bdc3300bbd97b85e50074776edb1d4fe5a1cc9eda517ec0465cc4bf7923e71bf" + "xero.json": "7488788caef5e5bfdc9597f34cab944eceb3d03112c5c14c6c43599031b1b421", + "xero_assets.json": "5a2ee47426d950ccf3d556ce303fca8d9db8d1f29bee6344788d941851ec5455", + "youtube.json": "24e2618cb16e13d5cd553713bef34a74f786abe290156f9705a792ddabee10fe", + "zoom.json": "00b19820a29bc2c1e01108a940ef4421f7ccc3e975d89bed81f3682ef805f945", + "zuora.json": "16e546dc1145fedb33639506595d484102227dac9ad4f8dd1f2442a3c6454320" }