From 06e5948a55fd09b3d8f7c4dde802e7427d7aa649 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 5 May 2026 08:56:26 +0000
Subject: [PATCH 01/12] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index daa2a129..3faaddc6 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 658
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-63b63d8be16530f04e4c07443b8f3ed2554e65dd6343d1ac13a48f89c2cf9fc4.yml
-openapi_spec_hash: 6f72f97fd9545f3ecda586de840c68ee
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-beaf81b82a6dc05b581a168ceb11a4666d814c87186a95543f99e4c66c16090d.yml
+openapi_spec_hash: 0b7e1b7e24ad10d7e7b268b8ab9e7df2
config_hash: 88e4af508ede520a45a0563d9cf077cc
From adc67307096350666c53204150fbb30a14cb9a7e Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Tue, 5 May 2026 10:41:52 +0000
Subject: [PATCH 02/12] feat(api): aggregated API specs update
---
.stats.yml | 4 +-
src/gcore/resources/waap/analytics.py | 252 ++++++++++++++++++
.../waap/analytics_get_requests_params.py | 80 ++++++
.../analytics_get_traffic_filtered_params.py | 80 ++++++
.../waap/domains/waap_request_details.py | 6 +
src/gcore/types/waap/waap_request_summary.py | 6 +
tests/api_resources/waap/test_analytics.py | 48 ++++
7 files changed, 474 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 3faaddc6..dc90c746 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 658
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-beaf81b82a6dc05b581a168ceb11a4666d814c87186a95543f99e4c66c16090d.yml
-openapi_spec_hash: 0b7e1b7e24ad10d7e7b268b8ab9e7df2
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-49a48cd48270c9e72f277d36d87dc605e6f225755093efee47f206c428ce2486.yml
+openapi_spec_hash: b86bc8f93f6ae74dc966ed86fbf0ac68
config_hash: 88e4af508ede520a45a0563d9cf077cc
diff --git a/src/gcore/resources/waap/analytics.py b/src/gcore/resources/waap/analytics.py
index a0a8389f..0ce5c252 100644
--- a/src/gcore/resources/waap/analytics.py
+++ b/src/gcore/resources/waap/analytics.py
@@ -133,21 +133,33 @@ def get_requests(
exclude_countries: SequenceNotStr[str] | Omit = omit,
exclude_domains: Iterable[int] | Omit = omit,
exclude_ips: SequenceNotStr[str] | Omit = omit,
+ exclude_ja3: Optional[str] | Omit = omit,
+ exclude_organizations: SequenceNotStr[str] | Omit = omit,
exclude_reference_ids: SequenceNotStr[str] | Omit = omit,
exclude_security_rule_names: SequenceNotStr[str] | Omit = omit,
exclude_session_ids: SequenceNotStr[str] | Omit = omit,
+ exclude_tags: SequenceNotStr[str] | Omit = omit,
+ exclude_user_agent: Optional[str] | Omit = omit,
+ exclude_user_agent_clients: SequenceNotStr[str] | Omit = omit,
+ exclude_user_agent_devices: SequenceNotStr[str] | Omit = omit,
http_methods: List[Literal["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] | Omit = omit,
ips: SequenceNotStr[str] | Omit = omit,
+ ja3: Optional[str] | Omit = omit,
limit: int | Omit = omit,
offset: int | Omit = omit,
optional_action: List[Literal["captcha", "challenge"]] | Omit = omit,
ordering: str | Omit = omit,
+ organizations: SequenceNotStr[str] | Omit = omit,
path: Optional[str] | Omit = omit,
reference_ids: SequenceNotStr[str] | Omit = omit,
request_ids: SequenceNotStr[str] | Omit = omit,
security_rule_names: SequenceNotStr[str] | Omit = omit,
session_ids: SequenceNotStr[str] | Omit = omit,
status_codes: Iterable[int] | Omit = omit,
+ tags: SequenceNotStr[str] | Omit = omit,
+ user_agent: Optional[str] | Omit = omit,
+ user_agent_clients: SequenceNotStr[str] | Omit = omit,
+ user_agent_devices: SequenceNotStr[str] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -181,16 +193,40 @@ def get_requests(
exclude_ips: Exclude traffic data by client IP.
+ exclude_ja3: Exclude entries whose JA3 TLS client fingerprint equals the supplied value. Must
+ be exactly 32 hexadecimal characters (mixed case allowed) and is case-folded to
+ lowercase when the backend filter is built. Omit the parameter to apply no JA3
+ exclusion.
+
+ exclude_organizations: Exclude entries whose organization exactly equals any supplied value. Omit or
+ provide an empty list to apply no organization exclusion.
+
exclude_reference_ids: Exclude data by reference IDs.
exclude_security_rule_names: Exclude data by name of a security rule matched the request.
exclude_session_ids: Exclude data by session IDs.
+ exclude_tags: Exclude entries whose tag exactly equals any supplied value. Omit or provide an
+ empty list to apply no tag exclusion.
+
+ exclude_user_agent: Exclude entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text exclusion.
+
+ exclude_user_agent_clients: Exclude entries whose parsed user agent client exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent client exclusion.
+
+ exclude_user_agent_devices: Exclude entries whose parsed user agent device exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent device exclusion.
+
http_methods: Filter by HTTP methods
ips: Filter traffic data by client IP.
+ ja3: Filter by JA3 TLS client fingerprint. When present, the value must be exactly 32
+ hexadecimal characters (mixed case allowed) and is case-folded to lowercase when
+ the backend filter is built. Omit the parameter entirely to apply no JA3 filter.
+
limit: Number of items to return
offset: Number of items to skip
@@ -199,6 +235,9 @@ def get_requests(
ordering: Sort data by given field.
+ organizations: Include entries whose organization exactly equals any supplied value. Omit or
+ provide an empty list to apply no organization filter.
+
path: Filter by URL path with a glob-like pattern.
reference_ids: Filter data by reference IDs.
@@ -211,6 +250,18 @@ def get_requests(
status_codes: Filter data by HTTP response status code.
+ tags: Include entries whose tag exactly equals any supplied value. Omit or provide an
+ empty list to apply no tag filter.
+
+ user_agent: Include entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text filter.
+
+ user_agent_clients: Include entries whose parsed user agent client exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent client filter.
+
+ user_agent_devices: Include entries whose parsed user agent device exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent device filter.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -237,21 +288,33 @@ def get_requests(
"exclude_countries": exclude_countries,
"exclude_domains": exclude_domains,
"exclude_ips": exclude_ips,
+ "exclude_ja3": exclude_ja3,
+ "exclude_organizations": exclude_organizations,
"exclude_reference_ids": exclude_reference_ids,
"exclude_security_rule_names": exclude_security_rule_names,
"exclude_session_ids": exclude_session_ids,
+ "exclude_tags": exclude_tags,
+ "exclude_user_agent": exclude_user_agent,
+ "exclude_user_agent_clients": exclude_user_agent_clients,
+ "exclude_user_agent_devices": exclude_user_agent_devices,
"http_methods": http_methods,
"ips": ips,
+ "ja3": ja3,
"limit": limit,
"offset": offset,
"optional_action": optional_action,
"ordering": ordering,
+ "organizations": organizations,
"path": path,
"reference_ids": reference_ids,
"request_ids": request_ids,
"security_rule_names": security_rule_names,
"session_ids": session_ids,
"status_codes": status_codes,
+ "tags": tags,
+ "user_agent": user_agent,
+ "user_agent_clients": user_agent_clients,
+ "user_agent_devices": user_agent_devices,
},
analytics_get_requests_params.AnalyticsGetRequestsParams,
),
@@ -336,18 +399,30 @@ def get_traffic_filtered(
exclude_countries: SequenceNotStr[str] | Omit = omit,
exclude_domains: Iterable[int] | Omit = omit,
exclude_ips: SequenceNotStr[str] | Omit = omit,
+ exclude_ja3: Optional[str] | Omit = omit,
+ exclude_organizations: SequenceNotStr[str] | Omit = omit,
exclude_reference_ids: SequenceNotStr[str] | Omit = omit,
exclude_security_rule_names: SequenceNotStr[str] | Omit = omit,
exclude_session_ids: SequenceNotStr[str] | Omit = omit,
+ exclude_tags: SequenceNotStr[str] | Omit = omit,
+ exclude_user_agent: Optional[str] | Omit = omit,
+ exclude_user_agent_clients: SequenceNotStr[str] | Omit = omit,
+ exclude_user_agent_devices: SequenceNotStr[str] | Omit = omit,
http_methods: List[Literal["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] | Omit = omit,
ips: SequenceNotStr[str] | Omit = omit,
+ ja3: Optional[str] | Omit = omit,
optional_action: List[Literal["captcha", "challenge"]] | Omit = omit,
+ organizations: SequenceNotStr[str] | Omit = omit,
path: Optional[str] | Omit = omit,
reference_ids: SequenceNotStr[str] | Omit = omit,
request_ids: SequenceNotStr[str] | Omit = omit,
security_rule_names: SequenceNotStr[str] | Omit = omit,
session_ids: SequenceNotStr[str] | Omit = omit,
status_codes: Iterable[int] | Omit = omit,
+ tags: SequenceNotStr[str] | Omit = omit,
+ user_agent: Optional[str] | Omit = omit,
+ user_agent_clients: SequenceNotStr[str] | Omit = omit,
+ user_agent_devices: SequenceNotStr[str] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -387,18 +462,45 @@ def get_traffic_filtered(
exclude_ips: Exclude traffic data by client IP.
+ exclude_ja3: Exclude entries whose JA3 TLS client fingerprint equals the supplied value. Must
+ be exactly 32 hexadecimal characters (mixed case allowed) and is case-folded to
+ lowercase when the backend filter is built. Omit the parameter to apply no JA3
+ exclusion.
+
+ exclude_organizations: Exclude entries whose organization exactly equals any supplied value. Omit or
+ provide an empty list to apply no organization exclusion.
+
exclude_reference_ids: Exclude data by reference IDs.
exclude_security_rule_names: Exclude data by name of a security rule matched the request.
exclude_session_ids: Exclude data by session IDs.
+ exclude_tags: Exclude entries whose tag exactly equals any supplied value. Omit or provide an
+ empty list to apply no tag exclusion.
+
+ exclude_user_agent: Exclude entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text exclusion.
+
+ exclude_user_agent_clients: Exclude entries whose parsed user agent client exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent client exclusion.
+
+ exclude_user_agent_devices: Exclude entries whose parsed user agent device exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent device exclusion.
+
http_methods: Filter by HTTP methods
ips: Filter traffic data by client IP.
+ ja3: Filter by JA3 TLS client fingerprint. When present, the value must be exactly 32
+ hexadecimal characters (mixed case allowed) and is case-folded to lowercase when
+ the backend filter is built. Omit the parameter entirely to apply no JA3 filter.
+
optional_action: Filter data by optional action.
+ organizations: Include entries whose organization exactly equals any supplied value. Omit or
+ provide an empty list to apply no organization filter.
+
path: Filter by URL path with a glob-like pattern.
reference_ids: Filter data by reference IDs.
@@ -411,6 +513,18 @@ def get_traffic_filtered(
status_codes: Filter data by HTTP response status code.
+ tags: Include entries whose tag exactly equals any supplied value. Omit or provide an
+ empty list to apply no tag filter.
+
+ user_agent: Include entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text filter.
+
+ user_agent_clients: Include entries whose parsed user agent client exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent client filter.
+
+ user_agent_devices: Include entries whose parsed user agent device exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent device filter.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -438,18 +552,30 @@ def get_traffic_filtered(
"exclude_countries": exclude_countries,
"exclude_domains": exclude_domains,
"exclude_ips": exclude_ips,
+ "exclude_ja3": exclude_ja3,
+ "exclude_organizations": exclude_organizations,
"exclude_reference_ids": exclude_reference_ids,
"exclude_security_rule_names": exclude_security_rule_names,
"exclude_session_ids": exclude_session_ids,
+ "exclude_tags": exclude_tags,
+ "exclude_user_agent": exclude_user_agent,
+ "exclude_user_agent_clients": exclude_user_agent_clients,
+ "exclude_user_agent_devices": exclude_user_agent_devices,
"http_methods": http_methods,
"ips": ips,
+ "ja3": ja3,
"optional_action": optional_action,
+ "organizations": organizations,
"path": path,
"reference_ids": reference_ids,
"request_ids": request_ids,
"security_rule_names": security_rule_names,
"session_ids": session_ids,
"status_codes": status_codes,
+ "tags": tags,
+ "user_agent": user_agent,
+ "user_agent_clients": user_agent_clients,
+ "user_agent_devices": user_agent_devices,
},
analytics_get_traffic_filtered_params.AnalyticsGetTrafficFilteredParams,
),
@@ -558,21 +684,33 @@ def get_requests(
exclude_countries: SequenceNotStr[str] | Omit = omit,
exclude_domains: Iterable[int] | Omit = omit,
exclude_ips: SequenceNotStr[str] | Omit = omit,
+ exclude_ja3: Optional[str] | Omit = omit,
+ exclude_organizations: SequenceNotStr[str] | Omit = omit,
exclude_reference_ids: SequenceNotStr[str] | Omit = omit,
exclude_security_rule_names: SequenceNotStr[str] | Omit = omit,
exclude_session_ids: SequenceNotStr[str] | Omit = omit,
+ exclude_tags: SequenceNotStr[str] | Omit = omit,
+ exclude_user_agent: Optional[str] | Omit = omit,
+ exclude_user_agent_clients: SequenceNotStr[str] | Omit = omit,
+ exclude_user_agent_devices: SequenceNotStr[str] | Omit = omit,
http_methods: List[Literal["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] | Omit = omit,
ips: SequenceNotStr[str] | Omit = omit,
+ ja3: Optional[str] | Omit = omit,
limit: int | Omit = omit,
offset: int | Omit = omit,
optional_action: List[Literal["captcha", "challenge"]] | Omit = omit,
ordering: str | Omit = omit,
+ organizations: SequenceNotStr[str] | Omit = omit,
path: Optional[str] | Omit = omit,
reference_ids: SequenceNotStr[str] | Omit = omit,
request_ids: SequenceNotStr[str] | Omit = omit,
security_rule_names: SequenceNotStr[str] | Omit = omit,
session_ids: SequenceNotStr[str] | Omit = omit,
status_codes: Iterable[int] | Omit = omit,
+ tags: SequenceNotStr[str] | Omit = omit,
+ user_agent: Optional[str] | Omit = omit,
+ user_agent_clients: SequenceNotStr[str] | Omit = omit,
+ user_agent_devices: SequenceNotStr[str] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -606,16 +744,40 @@ def get_requests(
exclude_ips: Exclude traffic data by client IP.
+ exclude_ja3: Exclude entries whose JA3 TLS client fingerprint equals the supplied value. Must
+ be exactly 32 hexadecimal characters (mixed case allowed) and is case-folded to
+ lowercase when the backend filter is built. Omit the parameter to apply no JA3
+ exclusion.
+
+ exclude_organizations: Exclude entries whose organization exactly equals any supplied value. Omit or
+ provide an empty list to apply no organization exclusion.
+
exclude_reference_ids: Exclude data by reference IDs.
exclude_security_rule_names: Exclude data by name of a security rule matched the request.
exclude_session_ids: Exclude data by session IDs.
+ exclude_tags: Exclude entries whose tag exactly equals any supplied value. Omit or provide an
+ empty list to apply no tag exclusion.
+
+ exclude_user_agent: Exclude entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text exclusion.
+
+ exclude_user_agent_clients: Exclude entries whose parsed user agent client exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent client exclusion.
+
+ exclude_user_agent_devices: Exclude entries whose parsed user agent device exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent device exclusion.
+
http_methods: Filter by HTTP methods
ips: Filter traffic data by client IP.
+ ja3: Filter by JA3 TLS client fingerprint. When present, the value must be exactly 32
+ hexadecimal characters (mixed case allowed) and is case-folded to lowercase when
+ the backend filter is built. Omit the parameter entirely to apply no JA3 filter.
+
limit: Number of items to return
offset: Number of items to skip
@@ -624,6 +786,9 @@ def get_requests(
ordering: Sort data by given field.
+ organizations: Include entries whose organization exactly equals any supplied value. Omit or
+ provide an empty list to apply no organization filter.
+
path: Filter by URL path with a glob-like pattern.
reference_ids: Filter data by reference IDs.
@@ -636,6 +801,18 @@ def get_requests(
status_codes: Filter data by HTTP response status code.
+ tags: Include entries whose tag exactly equals any supplied value. Omit or provide an
+ empty list to apply no tag filter.
+
+ user_agent: Include entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text filter.
+
+ user_agent_clients: Include entries whose parsed user agent client exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent client filter.
+
+ user_agent_devices: Include entries whose parsed user agent device exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent device filter.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -662,21 +839,33 @@ def get_requests(
"exclude_countries": exclude_countries,
"exclude_domains": exclude_domains,
"exclude_ips": exclude_ips,
+ "exclude_ja3": exclude_ja3,
+ "exclude_organizations": exclude_organizations,
"exclude_reference_ids": exclude_reference_ids,
"exclude_security_rule_names": exclude_security_rule_names,
"exclude_session_ids": exclude_session_ids,
+ "exclude_tags": exclude_tags,
+ "exclude_user_agent": exclude_user_agent,
+ "exclude_user_agent_clients": exclude_user_agent_clients,
+ "exclude_user_agent_devices": exclude_user_agent_devices,
"http_methods": http_methods,
"ips": ips,
+ "ja3": ja3,
"limit": limit,
"offset": offset,
"optional_action": optional_action,
"ordering": ordering,
+ "organizations": organizations,
"path": path,
"reference_ids": reference_ids,
"request_ids": request_ids,
"security_rule_names": security_rule_names,
"session_ids": session_ids,
"status_codes": status_codes,
+ "tags": tags,
+ "user_agent": user_agent,
+ "user_agent_clients": user_agent_clients,
+ "user_agent_devices": user_agent_devices,
},
analytics_get_requests_params.AnalyticsGetRequestsParams,
),
@@ -761,18 +950,30 @@ async def get_traffic_filtered(
exclude_countries: SequenceNotStr[str] | Omit = omit,
exclude_domains: Iterable[int] | Omit = omit,
exclude_ips: SequenceNotStr[str] | Omit = omit,
+ exclude_ja3: Optional[str] | Omit = omit,
+ exclude_organizations: SequenceNotStr[str] | Omit = omit,
exclude_reference_ids: SequenceNotStr[str] | Omit = omit,
exclude_security_rule_names: SequenceNotStr[str] | Omit = omit,
exclude_session_ids: SequenceNotStr[str] | Omit = omit,
+ exclude_tags: SequenceNotStr[str] | Omit = omit,
+ exclude_user_agent: Optional[str] | Omit = omit,
+ exclude_user_agent_clients: SequenceNotStr[str] | Omit = omit,
+ exclude_user_agent_devices: SequenceNotStr[str] | Omit = omit,
http_methods: List[Literal["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]] | Omit = omit,
ips: SequenceNotStr[str] | Omit = omit,
+ ja3: Optional[str] | Omit = omit,
optional_action: List[Literal["captcha", "challenge"]] | Omit = omit,
+ organizations: SequenceNotStr[str] | Omit = omit,
path: Optional[str] | Omit = omit,
reference_ids: SequenceNotStr[str] | Omit = omit,
request_ids: SequenceNotStr[str] | Omit = omit,
security_rule_names: SequenceNotStr[str] | Omit = omit,
session_ids: SequenceNotStr[str] | Omit = omit,
status_codes: Iterable[int] | Omit = omit,
+ tags: SequenceNotStr[str] | Omit = omit,
+ user_agent: Optional[str] | Omit = omit,
+ user_agent_clients: SequenceNotStr[str] | Omit = omit,
+ user_agent_devices: SequenceNotStr[str] | Omit = omit,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
@@ -812,18 +1013,45 @@ async def get_traffic_filtered(
exclude_ips: Exclude traffic data by client IP.
+ exclude_ja3: Exclude entries whose JA3 TLS client fingerprint equals the supplied value. Must
+ be exactly 32 hexadecimal characters (mixed case allowed) and is case-folded to
+ lowercase when the backend filter is built. Omit the parameter to apply no JA3
+ exclusion.
+
+ exclude_organizations: Exclude entries whose organization exactly equals any supplied value. Omit or
+ provide an empty list to apply no organization exclusion.
+
exclude_reference_ids: Exclude data by reference IDs.
exclude_security_rule_names: Exclude data by name of a security rule matched the request.
exclude_session_ids: Exclude data by session IDs.
+ exclude_tags: Exclude entries whose tag exactly equals any supplied value. Omit or provide an
+ empty list to apply no tag exclusion.
+
+ exclude_user_agent: Exclude entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text exclusion.
+
+ exclude_user_agent_clients: Exclude entries whose parsed user agent client exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent client exclusion.
+
+ exclude_user_agent_devices: Exclude entries whose parsed user agent device exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent device exclusion.
+
http_methods: Filter by HTTP methods
ips: Filter traffic data by client IP.
+ ja3: Filter by JA3 TLS client fingerprint. When present, the value must be exactly 32
+ hexadecimal characters (mixed case allowed) and is case-folded to lowercase when
+ the backend filter is built. Omit the parameter entirely to apply no JA3 filter.
+
optional_action: Filter data by optional action.
+ organizations: Include entries whose organization exactly equals any supplied value. Omit or
+ provide an empty list to apply no organization filter.
+
path: Filter by URL path with a glob-like pattern.
reference_ids: Filter data by reference IDs.
@@ -836,6 +1064,18 @@ async def get_traffic_filtered(
status_codes: Filter data by HTTP response status code.
+ tags: Include entries whose tag exactly equals any supplied value. Omit or provide an
+ empty list to apply no tag filter.
+
+ user_agent: Include entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text filter.
+
+ user_agent_clients: Include entries whose parsed user agent client exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent client filter.
+
+ user_agent_devices: Include entries whose parsed user agent device exactly equals any supplied
+ value. Omit or provide an empty list to apply no user agent device filter.
+
extra_headers: Send extra headers
extra_query: Add additional query parameters to the request
@@ -863,18 +1103,30 @@ async def get_traffic_filtered(
"exclude_countries": exclude_countries,
"exclude_domains": exclude_domains,
"exclude_ips": exclude_ips,
+ "exclude_ja3": exclude_ja3,
+ "exclude_organizations": exclude_organizations,
"exclude_reference_ids": exclude_reference_ids,
"exclude_security_rule_names": exclude_security_rule_names,
"exclude_session_ids": exclude_session_ids,
+ "exclude_tags": exclude_tags,
+ "exclude_user_agent": exclude_user_agent,
+ "exclude_user_agent_clients": exclude_user_agent_clients,
+ "exclude_user_agent_devices": exclude_user_agent_devices,
"http_methods": http_methods,
"ips": ips,
+ "ja3": ja3,
"optional_action": optional_action,
+ "organizations": organizations,
"path": path,
"reference_ids": reference_ids,
"request_ids": request_ids,
"security_rule_names": security_rule_names,
"session_ids": session_ids,
"status_codes": status_codes,
+ "tags": tags,
+ "user_agent": user_agent,
+ "user_agent_clients": user_agent_clients,
+ "user_agent_devices": user_agent_devices,
},
analytics_get_traffic_filtered_params.AnalyticsGetTrafficFilteredParams,
),
diff --git a/src/gcore/types/waap/analytics_get_requests_params.py b/src/gcore/types/waap/analytics_get_requests_params.py
index 361e70ce..623a0121 100644
--- a/src/gcore/types/waap/analytics_get_requests_params.py
+++ b/src/gcore/types/waap/analytics_get_requests_params.py
@@ -47,6 +47,20 @@ class AnalyticsGetRequestsParams(TypedDict, total=False):
exclude_ips: SequenceNotStr[str]
"""Exclude traffic data by client IP."""
+ exclude_ja3: Optional[str]
+ """Exclude entries whose JA3 TLS client fingerprint equals the supplied value.
+
+ Must be exactly 32 hexadecimal characters (mixed case allowed) and is
+ case-folded to lowercase when the backend filter is built. Omit the parameter to
+ apply no JA3 exclusion.
+ """
+
+ exclude_organizations: SequenceNotStr[str]
+ """Exclude entries whose organization exactly equals any supplied value.
+
+ Omit or provide an empty list to apply no organization exclusion.
+ """
+
exclude_reference_ids: SequenceNotStr[str]
"""Exclude data by reference IDs."""
@@ -56,12 +70,46 @@ class AnalyticsGetRequestsParams(TypedDict, total=False):
exclude_session_ids: SequenceNotStr[str]
"""Exclude data by session IDs."""
+ exclude_tags: SequenceNotStr[str]
+ """Exclude entries whose tag exactly equals any supplied value.
+
+ Omit or provide an empty list to apply no tag exclusion.
+ """
+
+ exclude_user_agent: Optional[str]
+ """
+ Exclude entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text exclusion.
+ """
+
+ exclude_user_agent_clients: SequenceNotStr[str]
+ """Exclude entries whose parsed user agent client exactly equals any supplied
+ value.
+
+ Omit or provide an empty list to apply no user agent client exclusion.
+ """
+
+ exclude_user_agent_devices: SequenceNotStr[str]
+ """Exclude entries whose parsed user agent device exactly equals any supplied
+ value.
+
+ Omit or provide an empty list to apply no user agent device exclusion.
+ """
+
http_methods: List[Literal["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]]
"""Filter by HTTP methods"""
ips: SequenceNotStr[str]
"""Filter traffic data by client IP."""
+ ja3: Optional[str]
+ """Filter by JA3 TLS client fingerprint.
+
+ When present, the value must be exactly 32 hexadecimal characters (mixed case
+ allowed) and is case-folded to lowercase when the backend filter is built. Omit
+ the parameter entirely to apply no JA3 filter.
+ """
+
limit: int
"""Number of items to return"""
@@ -74,6 +122,12 @@ class AnalyticsGetRequestsParams(TypedDict, total=False):
ordering: str
"""Sort data by given field."""
+ organizations: SequenceNotStr[str]
+ """Include entries whose organization exactly equals any supplied value.
+
+ Omit or provide an empty list to apply no organization filter.
+ """
+
path: Optional[str]
"""Filter by URL path with a glob-like pattern."""
@@ -91,3 +145,29 @@ class AnalyticsGetRequestsParams(TypedDict, total=False):
status_codes: Iterable[int]
"""Filter data by HTTP response status code."""
+
+ tags: SequenceNotStr[str]
+ """Include entries whose tag exactly equals any supplied value.
+
+ Omit or provide an empty list to apply no tag filter.
+ """
+
+ user_agent: Optional[str]
+ """
+ Include entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text filter.
+ """
+
+ user_agent_clients: SequenceNotStr[str]
+ """Include entries whose parsed user agent client exactly equals any supplied
+ value.
+
+ Omit or provide an empty list to apply no user agent client filter.
+ """
+
+ user_agent_devices: SequenceNotStr[str]
+ """Include entries whose parsed user agent device exactly equals any supplied
+ value.
+
+ Omit or provide an empty list to apply no user agent device filter.
+ """
diff --git a/src/gcore/types/waap/analytics_get_traffic_filtered_params.py b/src/gcore/types/waap/analytics_get_traffic_filtered_params.py
index 211e1446..15ed0dda 100644
--- a/src/gcore/types/waap/analytics_get_traffic_filtered_params.py
+++ b/src/gcore/types/waap/analytics_get_traffic_filtered_params.py
@@ -57,6 +57,20 @@ class AnalyticsGetTrafficFilteredParams(TypedDict, total=False):
exclude_ips: SequenceNotStr[str]
"""Exclude traffic data by client IP."""
+ exclude_ja3: Optional[str]
+ """Exclude entries whose JA3 TLS client fingerprint equals the supplied value.
+
+ Must be exactly 32 hexadecimal characters (mixed case allowed) and is
+ case-folded to lowercase when the backend filter is built. Omit the parameter to
+ apply no JA3 exclusion.
+ """
+
+ exclude_organizations: SequenceNotStr[str]
+ """Exclude entries whose organization exactly equals any supplied value.
+
+ Omit or provide an empty list to apply no organization exclusion.
+ """
+
exclude_reference_ids: SequenceNotStr[str]
"""Exclude data by reference IDs."""
@@ -66,15 +80,55 @@ class AnalyticsGetTrafficFilteredParams(TypedDict, total=False):
exclude_session_ids: SequenceNotStr[str]
"""Exclude data by session IDs."""
+ exclude_tags: SequenceNotStr[str]
+ """Exclude entries whose tag exactly equals any supplied value.
+
+ Omit or provide an empty list to apply no tag exclusion.
+ """
+
+ exclude_user_agent: Optional[str]
+ """
+ Exclude entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text exclusion.
+ """
+
+ exclude_user_agent_clients: SequenceNotStr[str]
+ """Exclude entries whose parsed user agent client exactly equals any supplied
+ value.
+
+ Omit or provide an empty list to apply no user agent client exclusion.
+ """
+
+ exclude_user_agent_devices: SequenceNotStr[str]
+ """Exclude entries whose parsed user agent device exactly equals any supplied
+ value.
+
+ Omit or provide an empty list to apply no user agent device exclusion.
+ """
+
http_methods: List[Literal["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "TRACE"]]
"""Filter by HTTP methods"""
ips: SequenceNotStr[str]
"""Filter traffic data by client IP."""
+ ja3: Optional[str]
+ """Filter by JA3 TLS client fingerprint.
+
+ When present, the value must be exactly 32 hexadecimal characters (mixed case
+ allowed) and is case-folded to lowercase when the backend filter is built. Omit
+ the parameter entirely to apply no JA3 filter.
+ """
+
optional_action: List[Literal["captcha", "challenge"]]
"""Filter data by optional action."""
+ organizations: SequenceNotStr[str]
+ """Include entries whose organization exactly equals any supplied value.
+
+ Omit or provide an empty list to apply no organization filter.
+ """
+
path: Optional[str]
"""Filter by URL path with a glob-like pattern."""
@@ -92,3 +146,29 @@ class AnalyticsGetTrafficFilteredParams(TypedDict, total=False):
status_codes: Iterable[int]
"""Filter data by HTTP response status code."""
+
+ tags: SequenceNotStr[str]
+ """Include entries whose tag exactly equals any supplied value.
+
+ Omit or provide an empty list to apply no tag filter.
+ """
+
+ user_agent: Optional[str]
+ """
+ Include entries whose user agent contains the supplied text, case-insensitive
+ partial match. Omit the parameter to apply no user agent text filter.
+ """
+
+ user_agent_clients: SequenceNotStr[str]
+ """Include entries whose parsed user agent client exactly equals any supplied
+ value.
+
+ Omit or provide an empty list to apply no user agent client filter.
+ """
+
+ user_agent_devices: SequenceNotStr[str]
+ """Include entries whose parsed user agent device exactly equals any supplied
+ value.
+
+ Omit or provide an empty list to apply no user agent device filter.
+ """
diff --git a/src/gcore/types/waap/domains/waap_request_details.py b/src/gcore/types/waap/domains/waap_request_details.py
index 16475cd9..c44f4474 100644
--- a/src/gcore/types/waap/domains/waap_request_details.py
+++ b/src/gcore/types/waap/domains/waap_request_details.py
@@ -203,5 +203,11 @@ class WaapRequestDetails(BaseModel):
decision: Optional[Literal["passed", "allowed", "monitored", "blocked", ""]] = None
"""The decision made for processing the request through the WAAP."""
+ ja3: Optional[str] = None
+ """
+ JA3 TLS client fingerprint as a 32-character lowercase hexadecimal MD5 hash, or
+ an empty string when the record has no JA3 value.
+ """
+
optional_action: Optional[Literal["captcha", "challenge", ""]] = None
"""An optional action that may be applied in addition to the primary decision."""
diff --git a/src/gcore/types/waap/waap_request_summary.py b/src/gcore/types/waap/waap_request_summary.py
index 22be6aba..89250e5e 100644
--- a/src/gcore/types/waap/waap_request_summary.py
+++ b/src/gcore/types/waap/waap_request_summary.py
@@ -73,6 +73,12 @@ class WaapRequestSummary(BaseModel):
http_version: Optional[str] = None
"""HTTP version of request"""
+ ja3: Optional[str] = None
+ """
+ JA3 TLS client fingerprint as a 32-character lowercase hexadecimal MD5 hash, or
+ an empty string when the record has no JA3 value.
+ """
+
scheme: Optional[str] = None
"""The URI scheme of the request that generated an event"""
diff --git a/tests/api_resources/waap/test_analytics.py b/tests/api_resources/waap/test_analytics.py
index adae66f5..d46210a4 100644
--- a/tests/api_resources/waap/test_analytics.py
+++ b/tests/api_resources/waap/test_analytics.py
@@ -87,21 +87,33 @@ def test_method_get_requests_with_all_params(self, client: Gcore) -> None:
exclude_countries=["DE", "MY"],
exclude_domains=[0],
exclude_ips=["1.2.3.4", "2001:678:194::3c25:ddad"],
+ exclude_ja3="e7d705a3286e19ea42f587b344ee6865",
+ exclude_organizations=["Acme corp"],
exclude_reference_ids=["210b9798eb53baa4e69d31c1071cf03d"],
exclude_security_rule_names=["SQL injection"],
exclude_session_ids=["210b9798eb53baa4e69d31c1071cf03d"],
+ exclude_tags=["mousedevice"],
+ exclude_user_agent="python-requests",
+ exclude_user_agent_clients=["OpenAI GPTBot", "Uptimerobot"],
+ exclude_user_agent_devices=["SMART TV"],
http_methods=["GET", "HEAD"],
ips=["1.2.3.4", " 2001:678:194::3c25:ddad"],
+ ja3="e7d705a3286e19ea42f587b344ee6865",
limit=0,
offset=0,
optional_action=["captcha", "challenge"],
ordering="userAgent",
+ organizations=["Example Org", "Acme Corp"],
path="/home",
reference_ids=["210b9798eb53baa4e69d31c1071cf03d"],
request_ids=["210b9798eb53baa4e69d31c1071cf03d-852383"],
security_rule_names=["SQL injection"],
session_ids=["210b9798eb53baa4e69d31c1071cf03d"],
status_codes=[100],
+ tags=["evasiveclient", "injectionattack"],
+ user_agent="Mozilla/5.0",
+ user_agent_clients=["Chrome", "Firefox"],
+ user_agent_devices=["mac", "Nokia", "PlayStation"],
)
assert_matches_type(SyncOffsetPage[WaapRequestSummary], analytics, path=["response"])
@@ -195,18 +207,30 @@ def test_method_get_traffic_filtered_with_all_params(self, client: Gcore) -> Non
exclude_countries=["DE", "MY"],
exclude_domains=[0],
exclude_ips=["1.2.3.4", "2001:678:194::3c25:ddad"],
+ exclude_ja3="e7d705a3286e19ea42f587b344ee6865",
+ exclude_organizations=["Acme corp"],
exclude_reference_ids=["210b9798eb53baa4e69d31c1071cf03d"],
exclude_security_rule_names=["SQL injection"],
exclude_session_ids=["210b9798eb53baa4e69d31c1071cf03d"],
+ exclude_tags=["mousedevice"],
+ exclude_user_agent="python-requests",
+ exclude_user_agent_clients=["OpenAI GPTBot", "Uptimerobot"],
+ exclude_user_agent_devices=["SMART TV"],
http_methods=["GET", "HEAD"],
ips=["1.2.3.4", " 2001:678:194::3c25:ddad"],
+ ja3="e7d705a3286e19ea42f587b344ee6865",
optional_action=["captcha", "challenge"],
+ organizations=["Example Org", "Acme Corp"],
path="/home",
reference_ids=["210b9798eb53baa4e69d31c1071cf03d"],
request_ids=["210b9798eb53baa4e69d31c1071cf03d-852383"],
security_rule_names=["SQL injection"],
session_ids=["210b9798eb53baa4e69d31c1071cf03d"],
status_codes=[100],
+ tags=["evasiveclient", "injectionattack"],
+ user_agent="Mozilla/5.0",
+ user_agent_clients=["Chrome", "Firefox"],
+ user_agent_devices=["mac", "Nokia", "PlayStation"],
)
assert_matches_type(AnalyticsGetTrafficFilteredResponse, analytics, path=["response"])
@@ -306,21 +330,33 @@ async def test_method_get_requests_with_all_params(self, async_client: AsyncGcor
exclude_countries=["DE", "MY"],
exclude_domains=[0],
exclude_ips=["1.2.3.4", "2001:678:194::3c25:ddad"],
+ exclude_ja3="e7d705a3286e19ea42f587b344ee6865",
+ exclude_organizations=["Acme corp"],
exclude_reference_ids=["210b9798eb53baa4e69d31c1071cf03d"],
exclude_security_rule_names=["SQL injection"],
exclude_session_ids=["210b9798eb53baa4e69d31c1071cf03d"],
+ exclude_tags=["mousedevice"],
+ exclude_user_agent="python-requests",
+ exclude_user_agent_clients=["OpenAI GPTBot", "Uptimerobot"],
+ exclude_user_agent_devices=["SMART TV"],
http_methods=["GET", "HEAD"],
ips=["1.2.3.4", " 2001:678:194::3c25:ddad"],
+ ja3="e7d705a3286e19ea42f587b344ee6865",
limit=0,
offset=0,
optional_action=["captcha", "challenge"],
ordering="userAgent",
+ organizations=["Example Org", "Acme Corp"],
path="/home",
reference_ids=["210b9798eb53baa4e69d31c1071cf03d"],
request_ids=["210b9798eb53baa4e69d31c1071cf03d-852383"],
security_rule_names=["SQL injection"],
session_ids=["210b9798eb53baa4e69d31c1071cf03d"],
status_codes=[100],
+ tags=["evasiveclient", "injectionattack"],
+ user_agent="Mozilla/5.0",
+ user_agent_clients=["Chrome", "Firefox"],
+ user_agent_devices=["mac", "Nokia", "PlayStation"],
)
assert_matches_type(AsyncOffsetPage[WaapRequestSummary], analytics, path=["response"])
@@ -414,18 +450,30 @@ async def test_method_get_traffic_filtered_with_all_params(self, async_client: A
exclude_countries=["DE", "MY"],
exclude_domains=[0],
exclude_ips=["1.2.3.4", "2001:678:194::3c25:ddad"],
+ exclude_ja3="e7d705a3286e19ea42f587b344ee6865",
+ exclude_organizations=["Acme corp"],
exclude_reference_ids=["210b9798eb53baa4e69d31c1071cf03d"],
exclude_security_rule_names=["SQL injection"],
exclude_session_ids=["210b9798eb53baa4e69d31c1071cf03d"],
+ exclude_tags=["mousedevice"],
+ exclude_user_agent="python-requests",
+ exclude_user_agent_clients=["OpenAI GPTBot", "Uptimerobot"],
+ exclude_user_agent_devices=["SMART TV"],
http_methods=["GET", "HEAD"],
ips=["1.2.3.4", " 2001:678:194::3c25:ddad"],
+ ja3="e7d705a3286e19ea42f587b344ee6865",
optional_action=["captcha", "challenge"],
+ organizations=["Example Org", "Acme Corp"],
path="/home",
reference_ids=["210b9798eb53baa4e69d31c1071cf03d"],
request_ids=["210b9798eb53baa4e69d31c1071cf03d-852383"],
security_rule_names=["SQL injection"],
session_ids=["210b9798eb53baa4e69d31c1071cf03d"],
status_codes=[100],
+ tags=["evasiveclient", "injectionattack"],
+ user_agent="Mozilla/5.0",
+ user_agent_clients=["Chrome", "Firefox"],
+ user_agent_devices=["mac", "Nokia", "PlayStation"],
)
assert_matches_type(AnalyticsGetTrafficFilteredResponse, analytics, path=["response"])
From f5efa161e613f3dd5b9078edf87b1ff09c6d990b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 6 May 2026 10:49:33 +0000
Subject: [PATCH 03/12] feat(api): aggregated API specs update
---
.stats.yml | 4 +-
.../types/cdn/origin_group_create_params.py | 72 +++++++++++++++++-
.../types/cdn/origin_group_replace_params.py | 72 +++++++++++++++++-
.../types/cdn/origin_group_update_params.py | 72 +++++++++++++++++-
src/gcore/types/cdn/origin_groups.py | 74 ++++++++++++++++++-
5 files changed, 280 insertions(+), 14 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index dc90c746..489f53c5 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 658
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-49a48cd48270c9e72f277d36d87dc605e6f225755093efee47f206c428ce2486.yml
-openapi_spec_hash: b86bc8f93f6ae74dc966ed86fbf0ac68
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-82db99348d2190a3c196adc12baac374facc672e882539e8518c7b85058c47ee.yml
+openapi_spec_hash: ae93d73931883d82017b3acd3c14eabd
config_hash: 88e4af508ede520a45a0563d9cf077cc
diff --git a/src/gcore/types/cdn/origin_group_create_params.py b/src/gcore/types/cdn/origin_group_create_params.py
index 8efbd7d2..4620451e 100644
--- a/src/gcore/types/cdn/origin_group_create_params.py
+++ b/src/gcore/types/cdn/origin_group_create_params.py
@@ -14,6 +14,8 @@
"NoneAuthSourceChangeHostSource",
"NoneAuthSourceChangeS3Source",
"NoneAuthSourceChangeS3SourceConfig",
+ "NoneAuthSourceChangeFastedgeSource",
+ "NoneAuthSourceChangeFastedgeSourceConfig",
"AwsSignatureV4",
"AwsSignatureV4Auth",
]
@@ -188,20 +190,84 @@ class NoneAuthSourceChangeS3Source(TypedDict, total=False):
from this origin instead of the default.
"""
- origin_type: Literal["host", "s3"]
- """Origin type. Present in responses only for S3 sources.
+ origin_type: Literal["host", "s3", "fastedge"]
+ """Origin type. Present in responses for S3 and FastEdge sources.
Possible values:
- **host** - A source server or endpoint from which content is fetched.
- **s3** - S3 storage with either AWS v4 authentication or public access.
+ - **fastedge** - A FastEdge application served directly from the local FastEdge
+ runtime on the edge node, identified by `app_id`.
"""
tag: str
"""Tag for the origin source."""
-NoneAuthSource: TypeAlias = Union[NoneAuthSourceChangeHostSource, NoneAuthSourceChangeS3Source]
+class NoneAuthSourceChangeFastedgeSourceConfig(TypedDict, total=False):
+ """FastEdge application configuration. Required when `origin_type` is `fastedge`."""
+
+ app_id: Required[str]
+ """
+ ID of the FastEdge application served as origin (string, matching the existing
+ fastedge option's convention). The CDN dispatches requests to the local FastEdge
+ runtime on the edge node using this identifier. The application must belong to
+ the requesting client, be enabled, and have `wasi-http` API type.
+ """
+
+
+class NoneAuthSourceChangeFastedgeSource(TypedDict, total=False):
+ config: Required[NoneAuthSourceChangeFastedgeSourceConfig]
+ """FastEdge application configuration. Required when `origin_type` is `fastedge`."""
+
+ origin_type: Required[Literal["host", "s3", "fastedge"]]
+ """Origin type. Present in responses for S3 and FastEdge sources.
+
+ Possible values:
+
+ - **host** - A source server or endpoint from which content is fetched.
+ - **s3** - S3 storage with either AWS v4 authentication or public access.
+ - **fastedge** - A FastEdge application served directly from the local FastEdge
+ runtime on the edge node, identified by `app_id`.
+ """
+
+ backup: bool
+ """
+ Defines whether the origin is a backup, meaning that it will not be used until
+ one of active origins become unavailable.
+
+ Possible values:
+
+ - **true** - Origin is a backup.
+ - **false** - Origin is not a backup.
+ """
+
+ enabled: bool
+ """Enables or disables an origin source in the origin group.
+
+ Possible values:
+
+ - **true** - Origin is enabled and the CDN uses it to pull content.
+ - **false** - Origin is disabled and the CDN does not use it to pull content.
+
+ Origin group must contain at least one enabled origin.
+ """
+
+ host_header_override: Optional[str]
+ """Per-origin Host header override.
+
+ When set, the CDN sends this value as the Host header when requesting content
+ from this origin instead of the default.
+ """
+
+ tag: str
+ """Tag for the origin source."""
+
+
+NoneAuthSource: TypeAlias = Union[
+ NoneAuthSourceChangeHostSource, NoneAuthSourceChangeS3Source, NoneAuthSourceChangeFastedgeSource
+]
class AwsSignatureV4(TypedDict, total=False):
diff --git a/src/gcore/types/cdn/origin_group_replace_params.py b/src/gcore/types/cdn/origin_group_replace_params.py
index a8694a66..4dac9f00 100644
--- a/src/gcore/types/cdn/origin_group_replace_params.py
+++ b/src/gcore/types/cdn/origin_group_replace_params.py
@@ -14,6 +14,8 @@
"NoneAuthSourceChangeHostSource",
"NoneAuthSourceChangeS3Source",
"NoneAuthSourceChangeS3SourceConfig",
+ "NoneAuthSourceChangeFastedgeSource",
+ "NoneAuthSourceChangeFastedgeSourceConfig",
"AwsSignatureV4",
"AwsSignatureV4Auth",
]
@@ -196,20 +198,84 @@ class NoneAuthSourceChangeS3Source(TypedDict, total=False):
from this origin instead of the default.
"""
- origin_type: Literal["host", "s3"]
- """Origin type. Present in responses only for S3 sources.
+ origin_type: Literal["host", "s3", "fastedge"]
+ """Origin type. Present in responses for S3 and FastEdge sources.
Possible values:
- **host** - A source server or endpoint from which content is fetched.
- **s3** - S3 storage with either AWS v4 authentication or public access.
+ - **fastedge** - A FastEdge application served directly from the local FastEdge
+ runtime on the edge node, identified by `app_id`.
"""
tag: str
"""Tag for the origin source."""
-NoneAuthSource: TypeAlias = Union[NoneAuthSourceChangeHostSource, NoneAuthSourceChangeS3Source]
+class NoneAuthSourceChangeFastedgeSourceConfig(TypedDict, total=False):
+ """FastEdge application configuration. Required when `origin_type` is `fastedge`."""
+
+ app_id: Required[str]
+ """
+ ID of the FastEdge application served as origin (string, matching the existing
+ fastedge option's convention). The CDN dispatches requests to the local FastEdge
+ runtime on the edge node using this identifier. The application must belong to
+ the requesting client, be enabled, and have `wasi-http` API type.
+ """
+
+
+class NoneAuthSourceChangeFastedgeSource(TypedDict, total=False):
+ config: Required[NoneAuthSourceChangeFastedgeSourceConfig]
+ """FastEdge application configuration. Required when `origin_type` is `fastedge`."""
+
+ origin_type: Required[Literal["host", "s3", "fastedge"]]
+ """Origin type. Present in responses for S3 and FastEdge sources.
+
+ Possible values:
+
+ - **host** - A source server or endpoint from which content is fetched.
+ - **s3** - S3 storage with either AWS v4 authentication or public access.
+ - **fastedge** - A FastEdge application served directly from the local FastEdge
+ runtime on the edge node, identified by `app_id`.
+ """
+
+ backup: bool
+ """
+ Defines whether the origin is a backup, meaning that it will not be used until
+ one of active origins become unavailable.
+
+ Possible values:
+
+ - **true** - Origin is a backup.
+ - **false** - Origin is not a backup.
+ """
+
+ enabled: bool
+ """Enables or disables an origin source in the origin group.
+
+ Possible values:
+
+ - **true** - Origin is enabled and the CDN uses it to pull content.
+ - **false** - Origin is disabled and the CDN does not use it to pull content.
+
+ Origin group must contain at least one enabled origin.
+ """
+
+ host_header_override: Optional[str]
+ """Per-origin Host header override.
+
+ When set, the CDN sends this value as the Host header when requesting content
+ from this origin instead of the default.
+ """
+
+ tag: str
+ """Tag for the origin source."""
+
+
+NoneAuthSource: TypeAlias = Union[
+ NoneAuthSourceChangeHostSource, NoneAuthSourceChangeS3Source, NoneAuthSourceChangeFastedgeSource
+]
class AwsSignatureV4(TypedDict, total=False):
diff --git a/src/gcore/types/cdn/origin_group_update_params.py b/src/gcore/types/cdn/origin_group_update_params.py
index 63a0cb0f..57731be1 100644
--- a/src/gcore/types/cdn/origin_group_update_params.py
+++ b/src/gcore/types/cdn/origin_group_update_params.py
@@ -14,6 +14,8 @@
"NoneAuthSourceChangeHostSource",
"NoneAuthSourceChangeS3Source",
"NoneAuthSourceChangeS3SourceConfig",
+ "NoneAuthSourceChangeFastedgeSource",
+ "NoneAuthSourceChangeFastedgeSourceConfig",
"AwsSignatureV4",
"AwsSignatureV4Auth",
]
@@ -196,20 +198,84 @@ class NoneAuthSourceChangeS3Source(TypedDict, total=False):
from this origin instead of the default.
"""
- origin_type: Literal["host", "s3"]
- """Origin type. Present in responses only for S3 sources.
+ origin_type: Literal["host", "s3", "fastedge"]
+ """Origin type. Present in responses for S3 and FastEdge sources.
Possible values:
- **host** - A source server or endpoint from which content is fetched.
- **s3** - S3 storage with either AWS v4 authentication or public access.
+ - **fastedge** - A FastEdge application served directly from the local FastEdge
+ runtime on the edge node, identified by `app_id`.
"""
tag: str
"""Tag for the origin source."""
-NoneAuthSource: TypeAlias = Union[NoneAuthSourceChangeHostSource, NoneAuthSourceChangeS3Source]
+class NoneAuthSourceChangeFastedgeSourceConfig(TypedDict, total=False):
+ """FastEdge application configuration. Required when `origin_type` is `fastedge`."""
+
+ app_id: Required[str]
+ """
+ ID of the FastEdge application served as origin (string, matching the existing
+ fastedge option's convention). The CDN dispatches requests to the local FastEdge
+ runtime on the edge node using this identifier. The application must belong to
+ the requesting client, be enabled, and have `wasi-http` API type.
+ """
+
+
+class NoneAuthSourceChangeFastedgeSource(TypedDict, total=False):
+ config: Required[NoneAuthSourceChangeFastedgeSourceConfig]
+ """FastEdge application configuration. Required when `origin_type` is `fastedge`."""
+
+ origin_type: Required[Literal["host", "s3", "fastedge"]]
+ """Origin type. Present in responses for S3 and FastEdge sources.
+
+ Possible values:
+
+ - **host** - A source server or endpoint from which content is fetched.
+ - **s3** - S3 storage with either AWS v4 authentication or public access.
+ - **fastedge** - A FastEdge application served directly from the local FastEdge
+ runtime on the edge node, identified by `app_id`.
+ """
+
+ backup: bool
+ """
+ Defines whether the origin is a backup, meaning that it will not be used until
+ one of active origins become unavailable.
+
+ Possible values:
+
+ - **true** - Origin is a backup.
+ - **false** - Origin is not a backup.
+ """
+
+ enabled: bool
+ """Enables or disables an origin source in the origin group.
+
+ Possible values:
+
+ - **true** - Origin is enabled and the CDN uses it to pull content.
+ - **false** - Origin is disabled and the CDN does not use it to pull content.
+
+ Origin group must contain at least one enabled origin.
+ """
+
+ host_header_override: Optional[str]
+ """Per-origin Host header override.
+
+ When set, the CDN sends this value as the Host header when requesting content
+ from this origin instead of the default.
+ """
+
+ tag: str
+ """Tag for the origin source."""
+
+
+NoneAuthSource: TypeAlias = Union[
+ NoneAuthSourceChangeHostSource, NoneAuthSourceChangeS3Source, NoneAuthSourceChangeFastedgeSource
+]
class AwsSignatureV4(TypedDict, total=False):
diff --git a/src/gcore/types/cdn/origin_groups.py b/src/gcore/types/cdn/origin_groups.py
index 43a63d92..c1b7e915 100644
--- a/src/gcore/types/cdn/origin_groups.py
+++ b/src/gcore/types/cdn/origin_groups.py
@@ -12,6 +12,8 @@
"NoneAuthSourceHostSourceResponse",
"NoneAuthSourceS3SourceResponse",
"NoneAuthSourceS3SourceResponseConfig",
+ "NoneAuthSourceFastedgeSourceResponse",
+ "NoneAuthSourceFastedgeSourceResponseConfig",
"AwsSignatureV4",
"AwsSignatureV4Auth",
]
@@ -112,13 +114,15 @@ class NoneAuthSourceS3SourceResponse(BaseModel):
config: NoneAuthSourceS3SourceResponseConfig
"""S3 storage configuration. Required when `origin_type` is `s3`."""
- origin_type: Literal["host", "s3"]
- """Origin type. Present in responses only for S3 sources.
+ origin_type: Literal["host", "s3", "fastedge"]
+ """Origin type. Present in responses for S3 and FastEdge sources.
Possible values:
- **host** - A source server or endpoint from which content is fetched.
- **s3** - S3 storage with either AWS v4 authentication or public access.
+ - **fastedge** - A FastEdge application served directly from the local FastEdge
+ runtime on the edge node, identified by `app_id`.
"""
backup: Optional[bool] = None
@@ -154,7 +158,71 @@ class NoneAuthSourceS3SourceResponse(BaseModel):
"""Tag for the origin source."""
-NoneAuthSource: TypeAlias = Union[NoneAuthSourceHostSourceResponse, NoneAuthSourceS3SourceResponse]
+class NoneAuthSourceFastedgeSourceResponseConfig(BaseModel):
+ """FastEdge application configuration. Required when `origin_type` is `fastedge`."""
+
+ app_id: str
+ """
+ ID of the FastEdge application served as origin (string, matching the existing
+ fastedge option's convention). The CDN dispatches requests to the local FastEdge
+ runtime on the edge node using this identifier. The application must belong to
+ the requesting client, be enabled, and have `wasi-http` API type.
+ """
+
+
+class NoneAuthSourceFastedgeSourceResponse(BaseModel):
+ """A FastEdge application origin source."""
+
+ config: NoneAuthSourceFastedgeSourceResponseConfig
+ """FastEdge application configuration. Required when `origin_type` is `fastedge`."""
+
+ origin_type: Literal["host", "s3", "fastedge"]
+ """Origin type. Present in responses for S3 and FastEdge sources.
+
+ Possible values:
+
+ - **host** - A source server or endpoint from which content is fetched.
+ - **s3** - S3 storage with either AWS v4 authentication or public access.
+ - **fastedge** - A FastEdge application served directly from the local FastEdge
+ runtime on the edge node, identified by `app_id`.
+ """
+
+ backup: Optional[bool] = None
+ """
+ Defines whether the origin is a backup, meaning that it will not be used until
+ one of active origins become unavailable.
+
+ Possible values:
+
+ - **true** - Origin is a backup.
+ - **false** - Origin is not a backup.
+ """
+
+ enabled: Optional[bool] = None
+ """Enables or disables an origin source in the origin group.
+
+ Possible values:
+
+ - **true** - Origin is enabled and the CDN uses it to pull content.
+ - **false** - Origin is disabled and the CDN does not use it to pull content.
+
+ Origin group must contain at least one enabled origin.
+ """
+
+ host_header_override: Optional[str] = None
+ """Per-origin Host header override.
+
+ When set, the CDN sends this value as the Host header when requesting content
+ from this origin instead of the default.
+ """
+
+ tag: Optional[str] = None
+ """Tag for the origin source."""
+
+
+NoneAuthSource: TypeAlias = Union[
+ NoneAuthSourceHostSourceResponse, NoneAuthSourceS3SourceResponse, NoneAuthSourceFastedgeSourceResponse
+]
class NoneAuth(BaseModel):
From 6722396ffbc3a6d73433b6393e7f5e812d0de4f2 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Wed, 6 May 2026 12:50:42 +0000
Subject: [PATCH 04/12] feat(api): aggregated API specs update
---
.stats.yml | 6 +-
src/gcore/resources/storage/api.md | 3 -
.../storage/object_storages/buckets.py | 312 +-----------------
.../types/storage/object_storages/__init__.py | 1 -
.../object_storages/bucket_update_params.py | 43 ---
.../storage/object_storages/test_buckets.py | 274 ---------------
6 files changed, 5 insertions(+), 634 deletions(-)
delete mode 100644 src/gcore/types/storage/object_storages/bucket_update_params.py
diff --git a/.stats.yml b/.stats.yml
index 489f53c5..e67e6aa7 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 658
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-82db99348d2190a3c196adc12baac374facc672e882539e8518c7b85058c47ee.yml
-openapi_spec_hash: ae93d73931883d82017b3acd3c14eabd
+configured_endpoints: 655
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-346d64735b866486d055d4e5930a2cd9ddbce10f5201c1d89befdcf60861a07c.yml
+openapi_spec_hash: 50d9727cc23f4e0de61ab2481909bd54
config_hash: 88e4af508ede520a45a0563d9cf077cc
diff --git a/src/gcore/resources/storage/api.md b/src/gcore/resources/storage/api.md
index a3a72e3e..b3a82664 100644
--- a/src/gcore/resources/storage/api.md
+++ b/src/gcore/resources/storage/api.md
@@ -54,10 +54,7 @@ from gcore.types.storage.object_storages import Bucket
Methods:
- client.storage.object_storages.buckets.create(storage_id, \*\*params) -> Bucket
-- client.storage.object_storages.buckets.update(bucket_name, \*, storage_id, \*\*params) -> Bucket
- client.storage.object_storages.buckets.list(storage_id, \*\*params) -> SyncOffsetPage[Bucket]
-- client.storage.object_storages.buckets.delete(bucket_name, \*, storage_id) -> None
-- client.storage.object_storages.buckets.get(bucket_name, \*, storage_id) -> Bucket
## SftpStorages
diff --git a/src/gcore/resources/storage/object_storages/buckets.py b/src/gcore/resources/storage/object_storages/buckets.py
index f29a71c3..7e48c9ec 100644
--- a/src/gcore/resources/storage/object_storages/buckets.py
+++ b/src/gcore/resources/storage/object_storages/buckets.py
@@ -4,7 +4,7 @@
import httpx
-from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from ...._utils import path_template, maybe_transform, async_maybe_transform
from ...._compat import cached_property
from ...._resource import SyncAPIResource, AsyncAPIResource
@@ -16,7 +16,7 @@
)
from ....pagination import SyncOffsetPage, AsyncOffsetPage
from ...._base_client import AsyncPaginator, make_request_options
-from ....types.storage.object_storages import bucket_list_params, bucket_create_params, bucket_update_params
+from ....types.storage.object_storages import bucket_list_params, bucket_create_params
from ....types.storage.object_storages.bucket import Bucket
__all__ = ["BucketsResource", "AsyncBucketsResource"]
@@ -77,62 +77,6 @@ def create(
cast_to=Bucket,
)
- def update(
- self,
- bucket_name: str,
- *,
- storage_id: int,
- cors: bucket_update_params.Cors | Omit = omit,
- lifecycle: bucket_update_params.Lifecycle | Omit = omit,
- policy: bucket_update_params.Policy | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> Bucket:
- """Updates bucket CORS, Lifecycle, and/or Policy settings.
-
- Supports partial
- updates - only specified fields will be modified.
-
- Lifecycle: set `expiration_days` to a positive integer to enable, null or 0 to
- remove. Negative values return 400. CORS: set `allowed_origins` to a non-empty
- array to configure, empty array to remove. Policy: set `is_public` to true/false
- to update.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not bucket_name:
- raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}")
- return self._patch(
- path_template(
- "/storage/v4/object_storages/{storage_id}/buckets/{bucket_name}",
- storage_id=storage_id,
- bucket_name=bucket_name,
- ),
- body=maybe_transform(
- {
- "cors": cors,
- "lifecycle": lifecycle,
- "policy": policy,
- },
- bucket_update_params.BucketUpdateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Bucket,
- )
-
def list(
self,
storage_id: int,
@@ -183,86 +127,6 @@ def list(
model=Bucket,
)
- def delete(
- self,
- bucket_name: str,
- *,
- storage_id: int,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """Removes a bucket from an S3-compatible storage.
-
- All objects in the bucket will
- be deleted.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not bucket_name:
- raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return self._delete(
- path_template(
- "/storage/v4/object_storages/{storage_id}/buckets/{bucket_name}",
- storage_id=storage_id,
- bucket_name=bucket_name,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- def get(
- self,
- bucket_name: str,
- *,
- storage_id: int,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> Bucket:
- """
- Returns bucket configuration including CORS, Lifecycle, and Policy settings in a
- consolidated response.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not bucket_name:
- raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}")
- return self._get(
- path_template(
- "/storage/v4/object_storages/{storage_id}/buckets/{bucket_name}",
- storage_id=storage_id,
- bucket_name=bucket_name,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Bucket,
- )
-
class AsyncBucketsResource(AsyncAPIResource):
@cached_property
@@ -319,62 +183,6 @@ async def create(
cast_to=Bucket,
)
- async def update(
- self,
- bucket_name: str,
- *,
- storage_id: int,
- cors: bucket_update_params.Cors | Omit = omit,
- lifecycle: bucket_update_params.Lifecycle | Omit = omit,
- policy: bucket_update_params.Policy | Omit = omit,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> Bucket:
- """Updates bucket CORS, Lifecycle, and/or Policy settings.
-
- Supports partial
- updates - only specified fields will be modified.
-
- Lifecycle: set `expiration_days` to a positive integer to enable, null or 0 to
- remove. Negative values return 400. CORS: set `allowed_origins` to a non-empty
- array to configure, empty array to remove. Policy: set `is_public` to true/false
- to update.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not bucket_name:
- raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}")
- return await self._patch(
- path_template(
- "/storage/v4/object_storages/{storage_id}/buckets/{bucket_name}",
- storage_id=storage_id,
- bucket_name=bucket_name,
- ),
- body=await async_maybe_transform(
- {
- "cors": cors,
- "lifecycle": lifecycle,
- "policy": policy,
- },
- bucket_update_params.BucketUpdateParams,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Bucket,
- )
-
def list(
self,
storage_id: int,
@@ -425,86 +233,6 @@ def list(
model=Bucket,
)
- async def delete(
- self,
- bucket_name: str,
- *,
- storage_id: int,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> None:
- """Removes a bucket from an S3-compatible storage.
-
- All objects in the bucket will
- be deleted.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not bucket_name:
- raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}")
- extra_headers = {"Accept": "*/*", **(extra_headers or {})}
- return await self._delete(
- path_template(
- "/storage/v4/object_storages/{storage_id}/buckets/{bucket_name}",
- storage_id=storage_id,
- bucket_name=bucket_name,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=NoneType,
- )
-
- async def get(
- self,
- bucket_name: str,
- *,
- storage_id: int,
- # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
- # The extra values given here take precedence over values defined on the client or passed to this method.
- extra_headers: Headers | None = None,
- extra_query: Query | None = None,
- extra_body: Body | None = None,
- timeout: float | httpx.Timeout | None | NotGiven = not_given,
- ) -> Bucket:
- """
- Returns bucket configuration including CORS, Lifecycle, and Policy settings in a
- consolidated response.
-
- Args:
- extra_headers: Send extra headers
-
- extra_query: Add additional query parameters to the request
-
- extra_body: Add additional JSON properties to the request
-
- timeout: Override the client-level default timeout for this request, in seconds
- """
- if not bucket_name:
- raise ValueError(f"Expected a non-empty value for `bucket_name` but received {bucket_name!r}")
- return await self._get(
- path_template(
- "/storage/v4/object_storages/{storage_id}/buckets/{bucket_name}",
- storage_id=storage_id,
- bucket_name=bucket_name,
- ),
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=Bucket,
- )
-
class BucketsResourceWithRawResponse:
def __init__(self, buckets: BucketsResource) -> None:
@@ -513,18 +241,9 @@ def __init__(self, buckets: BucketsResource) -> None:
self.create = to_raw_response_wrapper(
buckets.create,
)
- self.update = to_raw_response_wrapper(
- buckets.update,
- )
self.list = to_raw_response_wrapper(
buckets.list,
)
- self.delete = to_raw_response_wrapper(
- buckets.delete,
- )
- self.get = to_raw_response_wrapper(
- buckets.get,
- )
class AsyncBucketsResourceWithRawResponse:
@@ -534,18 +253,9 @@ def __init__(self, buckets: AsyncBucketsResource) -> None:
self.create = async_to_raw_response_wrapper(
buckets.create,
)
- self.update = async_to_raw_response_wrapper(
- buckets.update,
- )
self.list = async_to_raw_response_wrapper(
buckets.list,
)
- self.delete = async_to_raw_response_wrapper(
- buckets.delete,
- )
- self.get = async_to_raw_response_wrapper(
- buckets.get,
- )
class BucketsResourceWithStreamingResponse:
@@ -555,18 +265,9 @@ def __init__(self, buckets: BucketsResource) -> None:
self.create = to_streamed_response_wrapper(
buckets.create,
)
- self.update = to_streamed_response_wrapper(
- buckets.update,
- )
self.list = to_streamed_response_wrapper(
buckets.list,
)
- self.delete = to_streamed_response_wrapper(
- buckets.delete,
- )
- self.get = to_streamed_response_wrapper(
- buckets.get,
- )
class AsyncBucketsResourceWithStreamingResponse:
@@ -576,15 +277,6 @@ def __init__(self, buckets: AsyncBucketsResource) -> None:
self.create = async_to_streamed_response_wrapper(
buckets.create,
)
- self.update = async_to_streamed_response_wrapper(
- buckets.update,
- )
self.list = async_to_streamed_response_wrapper(
buckets.list,
)
- self.delete = async_to_streamed_response_wrapper(
- buckets.delete,
- )
- self.get = async_to_streamed_response_wrapper(
- buckets.get,
- )
diff --git a/src/gcore/types/storage/object_storages/__init__.py b/src/gcore/types/storage/object_storages/__init__.py
index 5bce0f48..9e6aa507 100644
--- a/src/gcore/types/storage/object_storages/__init__.py
+++ b/src/gcore/types/storage/object_storages/__init__.py
@@ -7,5 +7,4 @@
from .access_key_created import AccessKeyCreated as AccessKeyCreated
from .bucket_list_params import BucketListParams as BucketListParams
from .bucket_create_params import BucketCreateParams as BucketCreateParams
-from .bucket_update_params import BucketUpdateParams as BucketUpdateParams
from .access_key_list_params import AccessKeyListParams as AccessKeyListParams
diff --git a/src/gcore/types/storage/object_storages/bucket_update_params.py b/src/gcore/types/storage/object_storages/bucket_update_params.py
deleted file mode 100644
index 75b02927..00000000
--- a/src/gcore/types/storage/object_storages/bucket_update_params.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-from typing_extensions import Required, TypedDict
-
-from ...._types import SequenceNotStr
-
-__all__ = ["BucketUpdateParams", "Cors", "Lifecycle", "Policy"]
-
-
-class BucketUpdateParams(TypedDict, total=False):
- storage_id: Required[int]
-
- cors: Cors
-
- lifecycle: Lifecycle
-
- policy: Policy
-
-
-class Cors(TypedDict, total=False):
- allowed_origins: SequenceNotStr[str]
- """Web domains allowed to make direct browser requests.
-
- Send an empty array to remove CORS configuration.
- """
-
-
-class Lifecycle(TypedDict, total=False):
- expiration_days: int
- """Days before objects are automatically deleted.
-
- Set to a positive number to enable, or null/0 to remove the rule.
- """
-
-
-class Policy(TypedDict, total=False):
- is_public: bool
- """
- Set to true to allow unauthenticated object downloads, false to require valid S3
- credentials.
- """
diff --git a/tests/api_resources/storage/object_storages/test_buckets.py b/tests/api_resources/storage/object_storages/test_buckets.py
index 5bae6c0e..5f9c1325 100644
--- a/tests/api_resources/storage/object_storages/test_buckets.py
+++ b/tests/api_resources/storage/object_storages/test_buckets.py
@@ -52,59 +52,6 @@ def test_streaming_response_create(self, client: Gcore) -> None:
assert cast(Any, response.is_closed) is True
- @parametrize
- def test_method_update(self, client: Gcore) -> None:
- bucket = client.storage.object_storages.buckets.update(
- bucket_name="bucket_name",
- storage_id=0,
- )
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- def test_method_update_with_all_params(self, client: Gcore) -> None:
- bucket = client.storage.object_storages.buckets.update(
- bucket_name="bucket_name",
- storage_id=0,
- cors={"allowed_origins": ["https://example.com"]},
- lifecycle={"expiration_days": 30},
- policy={"is_public": True},
- )
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- def test_raw_response_update(self, client: Gcore) -> None:
- response = client.storage.object_storages.buckets.with_raw_response.update(
- bucket_name="bucket_name",
- storage_id=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- bucket = response.parse()
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- def test_streaming_response_update(self, client: Gcore) -> None:
- with client.storage.object_storages.buckets.with_streaming_response.update(
- bucket_name="bucket_name",
- storage_id=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- bucket = response.parse()
- assert_matches_type(Bucket, bucket, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @parametrize
- def test_path_params_update(self, client: Gcore) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"):
- client.storage.object_storages.buckets.with_raw_response.update(
- bucket_name="",
- storage_id=0,
- )
-
@parametrize
def test_method_list(self, client: Gcore) -> None:
bucket = client.storage.object_storages.buckets.list(
@@ -145,90 +92,6 @@ def test_streaming_response_list(self, client: Gcore) -> None:
assert cast(Any, response.is_closed) is True
- @parametrize
- def test_method_delete(self, client: Gcore) -> None:
- bucket = client.storage.object_storages.buckets.delete(
- bucket_name="bucket_name",
- storage_id=0,
- )
- assert bucket is None
-
- @parametrize
- def test_raw_response_delete(self, client: Gcore) -> None:
- response = client.storage.object_storages.buckets.with_raw_response.delete(
- bucket_name="bucket_name",
- storage_id=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- bucket = response.parse()
- assert bucket is None
-
- @parametrize
- def test_streaming_response_delete(self, client: Gcore) -> None:
- with client.storage.object_storages.buckets.with_streaming_response.delete(
- bucket_name="bucket_name",
- storage_id=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- bucket = response.parse()
- assert bucket is None
-
- assert cast(Any, response.is_closed) is True
-
- @parametrize
- def test_path_params_delete(self, client: Gcore) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"):
- client.storage.object_storages.buckets.with_raw_response.delete(
- bucket_name="",
- storage_id=0,
- )
-
- @parametrize
- def test_method_get(self, client: Gcore) -> None:
- bucket = client.storage.object_storages.buckets.get(
- bucket_name="bucket_name",
- storage_id=0,
- )
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- def test_raw_response_get(self, client: Gcore) -> None:
- response = client.storage.object_storages.buckets.with_raw_response.get(
- bucket_name="bucket_name",
- storage_id=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- bucket = response.parse()
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- def test_streaming_response_get(self, client: Gcore) -> None:
- with client.storage.object_storages.buckets.with_streaming_response.get(
- bucket_name="bucket_name",
- storage_id=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- bucket = response.parse()
- assert_matches_type(Bucket, bucket, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @parametrize
- def test_path_params_get(self, client: Gcore) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"):
- client.storage.object_storages.buckets.with_raw_response.get(
- bucket_name="",
- storage_id=0,
- )
-
class TestAsyncBuckets:
parametrize = pytest.mark.parametrize(
@@ -269,59 +132,6 @@ async def test_streaming_response_create(self, async_client: AsyncGcore) -> None
assert cast(Any, response.is_closed) is True
- @parametrize
- async def test_method_update(self, async_client: AsyncGcore) -> None:
- bucket = await async_client.storage.object_storages.buckets.update(
- bucket_name="bucket_name",
- storage_id=0,
- )
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- async def test_method_update_with_all_params(self, async_client: AsyncGcore) -> None:
- bucket = await async_client.storage.object_storages.buckets.update(
- bucket_name="bucket_name",
- storage_id=0,
- cors={"allowed_origins": ["https://example.com"]},
- lifecycle={"expiration_days": 30},
- policy={"is_public": True},
- )
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- async def test_raw_response_update(self, async_client: AsyncGcore) -> None:
- response = await async_client.storage.object_storages.buckets.with_raw_response.update(
- bucket_name="bucket_name",
- storage_id=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- bucket = await response.parse()
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- async def test_streaming_response_update(self, async_client: AsyncGcore) -> None:
- async with async_client.storage.object_storages.buckets.with_streaming_response.update(
- bucket_name="bucket_name",
- storage_id=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- bucket = await response.parse()
- assert_matches_type(Bucket, bucket, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @parametrize
- async def test_path_params_update(self, async_client: AsyncGcore) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"):
- await async_client.storage.object_storages.buckets.with_raw_response.update(
- bucket_name="",
- storage_id=0,
- )
-
@parametrize
async def test_method_list(self, async_client: AsyncGcore) -> None:
bucket = await async_client.storage.object_storages.buckets.list(
@@ -361,87 +171,3 @@ async def test_streaming_response_list(self, async_client: AsyncGcore) -> None:
assert_matches_type(AsyncOffsetPage[Bucket], bucket, path=["response"])
assert cast(Any, response.is_closed) is True
-
- @parametrize
- async def test_method_delete(self, async_client: AsyncGcore) -> None:
- bucket = await async_client.storage.object_storages.buckets.delete(
- bucket_name="bucket_name",
- storage_id=0,
- )
- assert bucket is None
-
- @parametrize
- async def test_raw_response_delete(self, async_client: AsyncGcore) -> None:
- response = await async_client.storage.object_storages.buckets.with_raw_response.delete(
- bucket_name="bucket_name",
- storage_id=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- bucket = await response.parse()
- assert bucket is None
-
- @parametrize
- async def test_streaming_response_delete(self, async_client: AsyncGcore) -> None:
- async with async_client.storage.object_storages.buckets.with_streaming_response.delete(
- bucket_name="bucket_name",
- storage_id=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- bucket = await response.parse()
- assert bucket is None
-
- assert cast(Any, response.is_closed) is True
-
- @parametrize
- async def test_path_params_delete(self, async_client: AsyncGcore) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"):
- await async_client.storage.object_storages.buckets.with_raw_response.delete(
- bucket_name="",
- storage_id=0,
- )
-
- @parametrize
- async def test_method_get(self, async_client: AsyncGcore) -> None:
- bucket = await async_client.storage.object_storages.buckets.get(
- bucket_name="bucket_name",
- storage_id=0,
- )
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- async def test_raw_response_get(self, async_client: AsyncGcore) -> None:
- response = await async_client.storage.object_storages.buckets.with_raw_response.get(
- bucket_name="bucket_name",
- storage_id=0,
- )
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- bucket = await response.parse()
- assert_matches_type(Bucket, bucket, path=["response"])
-
- @parametrize
- async def test_streaming_response_get(self, async_client: AsyncGcore) -> None:
- async with async_client.storage.object_storages.buckets.with_streaming_response.get(
- bucket_name="bucket_name",
- storage_id=0,
- ) as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- bucket = await response.parse()
- assert_matches_type(Bucket, bucket, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
- @parametrize
- async def test_path_params_get(self, async_client: AsyncGcore) -> None:
- with pytest.raises(ValueError, match=r"Expected a non-empty value for `bucket_name` but received ''"):
- await async_client.storage.object_storages.buckets.with_raw_response.get(
- bucket_name="",
- storage_id=0,
- )
From 227d229251317cfa2e9cc57d55e28f6bf85c6a7a Mon Sep 17 00:00:00 2001
From: Danil Krox
Date: Wed, 6 May 2026 19:35:43 +0200
Subject: [PATCH 05/12] feat: add cross-SDK sync and relax CI breaking-change
check for /release skill
---
.agents/skills/release/SKILL.md | 49 +++++++++++++++++++++++++++------
1 file changed, 41 insertions(+), 8 deletions(-)
diff --git a/.agents/skills/release/SKILL.md b/.agents/skills/release/SKILL.md
index e956f2d6..0e296f49 100644
--- a/.agents/skills/release/SKILL.md
+++ b/.agents/skills/release/SKILL.md
@@ -15,6 +15,8 @@ allowed-tools: >
Bash(gh pr merge * --repo G-Core/gcore-python *),
Bash(gh release view --repo G-Core/gcore-python *),
Bash(gh release edit * --repo G-Core/gcore-python *),
+ Bash(gh release view * --repo G-Core/gcore-go *),
+ Bash(gh release list --repo G-Core/gcore-go *),
Bash(sleep *)
---
@@ -23,7 +25,8 @@ allowed-tools: >
## Constraints
- **Repository**: `G-Core/gcore-python` (hardcoded, do not use for other repos)
-- **Allowed tools**: `gh` CLI (scoped to `G-Core/gcore-python`) and `Read`
+- **Allowed tools**: `gh` CLI (scoped to `G-Core/gcore-python` + read-only
+ `G-Core/gcore-go` releases) and `Read`
- **Never**: modify source code, force-push, delete branches, or merge without
explicit user confirmation
- **Release PRs** are created by `stainless-app[bot]` with title `release: {version}`
@@ -98,19 +101,41 @@ Fetch all three in parallel:
Within a product area, split into distinct **sub-areas** by resource type.
Do not lump unrelated resources into a single sub-area.
+### Step 2.5 — Check Go SDK Release (Cross-SDK Sync)
+
+Check whether `G-Core/gcore-go` already has a release for the same
+version. Both SDKs are generated from the same API specs and share version
+numbers, so matching releases cover the same underlying API changes.
+
+```bash
+gh release view v{VERSION} --repo G-Core/gcore-go --json tagName,body
+```
+
+- If a matching release **exists**, extract its Part 1 (everything before the
+ `## {VERSION}` auto-generated changelog heading). Store it as the **Go
+ reference notes** for use in Step 4.
+- If the release **does not exist** (exit code ≠ 0), proceed without reference.
+ This is expected when the Python SDK releases first.
+
+Do **not** display the Go notes to the user — they are an internal
+reference for wording alignment only.
+
### Step 3 — Check CI Status
```bash
gh pr checks {N} --repo G-Core/gcore-python --json name,state,bucket
```
-Exit codes: `0` = all pass, `8` = pending, `1` = failure.
+**Ignore `detect-breaking-changes`** when evaluating CI status — it is
+informational only. Breaking API changes are expected in release PRs and
+documented in the changelog. If it fails, note it for the user but do not
+treat it as a blocker.
-| Status | Action |
-|---|---|
-| exit `0` / all checks pass | Report **CI green**, proceed |
-| exit `8` / pending | Warn user checks are running. Ask: wait or proceed? |
-| exit `1` / failure | Show failing checks. **Do not offer to merge.** |
+After excluding `detect-breaking-changes`:
+
+- **All checks pass** — report CI green, proceed.
+- **Some checks pending** — warn user, ask: wait or proceed?
+- **Any check fails** — show failing checks, do not offer to merge.
### Step 4 — Generate Human-Readable Release Notes
@@ -149,6 +174,12 @@ We're excited to announce version {VERSION}!
- **Always use backtick-wrapped Python identifiers** for types, fields, methods.
Types use `PascalCase`, methods/fields use `snake_case`.
- **No commit hashes or links** in Part 1 (those are in Part 2).
+- **Cross-SDK alignment**: If Go reference notes were fetched in Step 2.5,
+ use them as a wording guide for overlapping API changes. For each change that
+ appears in both SDKs, match the Go description's phrasing and structure
+ while substituting Python identifiers (`snake_case` methods, `Optional[T]`
+ instead of `param.Opt[T]`, etc.). Python-only changes (SDK internals,
+ Python-specific fixes) have no Go counterpart — write those fresh.
- **Do not copy** the auto-generated changelog verbatim. Aggregate related
changes. Skip noise.
- **Omit `codegen metadata` and `aggregated API specs update`** entries unless
@@ -218,9 +249,11 @@ After merge, `stainless-app[bot]` auto-creates a GitHub Release.
| Situation | Action |
|---|---|
| No open release PR | Inform user, stop |
-| CI failing | Show failures, do not merge |
+| `detect-breaking-changes` fails | Informational only. Report to user, proceed with merge |
+| CI failing (other checks) | Show failures, do not merge |
| CI pending | Warn, ask user preference |
| Merge conflict | Report, suggest manual resolution |
| Merge fails | Report error, stop |
| Release not found after merge | Retry once after 10s, then report |
+| Go SDK release not found | Proceed without cross-SDK reference |
| `gh` CLI not authenticated | Report, suggest `gh auth login` |
From 8435c87ad8aa4ff3bdf21c29dea5bf3cc6827e75 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 7 May 2026 15:05:17 +0000
Subject: [PATCH 06/12] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index e67e6aa7..5a472ddc 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 655
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-346d64735b866486d055d4e5930a2cd9ddbce10f5201c1d89befdcf60861a07c.yml
-openapi_spec_hash: 50d9727cc23f4e0de61ab2481909bd54
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-993b39cc9b2618ff631a6a1a1801b8eca4747f66aa478fbeab0ce7a9f4b37717.yml
+openapi_spec_hash: 6e1b4ec62b4c482b9278a628f232f375
config_hash: 88e4af508ede520a45a0563d9cf077cc
From 9d56917be59224908e9953809511d9132a4a899b Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Thu, 7 May 2026 20:36:08 +0000
Subject: [PATCH 07/12] feat(api): aggregated API specs update
---
.stats.yml | 4 +-
src/gcore/resources/streaming/quality_sets.py | 12 ++-
src/gcore/resources/streaming/restreams.py | 88 +++++++++++++++----
.../resources/streaming/videos/videos.py | 30 ++++---
src/gcore/types/streaming/restream.py | 6 +-
.../types/streaming/restream_create_params.py | 6 +-
.../types/streaming/restream_list_params.py | 2 +-
.../types/streaming/restream_update_params.py | 6 +-
8 files changed, 114 insertions(+), 40 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 5a472ddc..93dd0f0c 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 655
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-993b39cc9b2618ff631a6a1a1801b8eca4747f66aa478fbeab0ce7a9f4b37717.yml
-openapi_spec_hash: 6e1b4ec62b4c482b9278a628f232f375
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-654176da11454546a55cd34a004f89ee9133d144f2f3d6f1b23701e85d645fb8.yml
+openapi_spec_hash: a96c0414ee2343a62ea3e4938bbccbd0
config_hash: 88e4af508ede520a45a0563d9cf077cc
diff --git a/src/gcore/resources/streaming/quality_sets.py b/src/gcore/resources/streaming/quality_sets.py
index 4aff7843..121f80d1 100644
--- a/src/gcore/resources/streaming/quality_sets.py
+++ b/src/gcore/resources/streaming/quality_sets.py
@@ -87,8 +87,10 @@ def list(
- Resolution: Determines the size of the video frame. I.e. 720p, 1080p, 4K, etc.
- Bitrate: Refers to the amount of data processed per unit of time.
- - Codec: Codec used for transcoding can significantly affect quality. Popular
- codecs include H.264 (AVC), H.265 (HEVC), and AV1.
+ - Codec: Codec used for transcoding can significantly affect quality. By
+ default, H.264 (AVC) is available from SD to 4K. As a premium encoding
+ feature, more advanced codecs like HEVC (H.265), AV1, and VP9 are also
+ available.
- Frame Rate: Determines how many frames per second are displayed. Common frame
rates include 24fps, 30fps, and 60fps.
- Color Depth and Chroma Subsampling: These settings determine the accuracy of
@@ -229,8 +231,10 @@ async def list(
- Resolution: Determines the size of the video frame. I.e. 720p, 1080p, 4K, etc.
- Bitrate: Refers to the amount of data processed per unit of time.
- - Codec: Codec used for transcoding can significantly affect quality. Popular
- codecs include H.264 (AVC), H.265 (HEVC), and AV1.
+ - Codec: Codec used for transcoding can significantly affect quality. By
+ default, H.264 (AVC) is available from SD to 4K. As a premium encoding
+ feature, more advanced codecs like HEVC (H.265), AV1, and VP9 are also
+ available.
- Frame Rate: Determines how many frames per second are displayed. Common frame
rates include 24fps, 30fps, and 60fps.
- Color Depth and Chroma Subsampling: These settings determine the accuracy of
diff --git a/src/gcore/resources/streaming/restreams.py b/src/gcore/resources/streaming/restreams.py
index d38b2183..1f27e987 100644
--- a/src/gcore/resources/streaming/restreams.py
+++ b/src/gcore/resources/streaming/restreams.py
@@ -54,7 +54,36 @@ def create(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
"""
- Create restream
+ Creates a new restream for a specified live stream.
+
+ Specify the target platform's URI (RTMP, RTMPS, or SRT) and the ID of the source
+ stream.
+
+ Restreaming allows you to broadcast a single live stream to multiple platforms
+ or servers simultaneously (e.g., Facebook, YouTube, or a custom media server).
+
+ **How it works:**
+
+ 1. Get credentials (stream URL/key or SRT URL) from the target platform.
+ 2. Create a restream in the Gcore system by specifying the target URI and the
+ source live stream.
+ 3. Start your live stream; it will be automatically pushed to the target
+ destination.
+
+ ```text
+ +-----------------------+
+ RTMP/RTMPS | | --------> Facebook (RTMP)
+ or ------> | Gcore Streaming | --------> YouTube (RTMPS)
+ SRT | | --------> Media server (SRT)
+ +-----------------------+ --------> Other RTMP/SRT targets
+ ```
+
+ **Supported combinations:** RTMP → RTMP, RTMPS → RTMPS, RTMP → SRT, SRT → SRT,
+ SRT → RTMP. For SRT targets, only `mode=caller` is supported (Gcore initiates a
+ PUSH connection).
+
+ Source stream parameters (bitrate, codecs, resolution) are sent "as is". Ensure
+ they match the destination requirements.
Args:
extra_headers: Send extra headers
@@ -88,7 +117,7 @@ def update(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Restream:
"""
- Updates restream settings
+ Updates restream settings, such as the target URI or active status
Args:
extra_headers: Send extra headers
@@ -119,12 +148,11 @@ def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> SyncPageStreaming[Restream]:
- """Returns a list of created restreams
+ """
+ Returns a list of all restreams created in your account
Args:
- page: Query parameter.
-
- Use it to list the paginated content
+ page: Use it to list the paginated content
extra_headers: Send extra headers
@@ -159,7 +187,7 @@ def delete(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
"""
- Delete restream
+ Deletes a restream and stops the broadcast to the target destination
Args:
extra_headers: Send extra headers
@@ -191,7 +219,7 @@ def get(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Restream:
"""
- Returns restream details
+ Returns configuration and status details for a specific restream
Args:
extra_headers: Send extra headers
@@ -243,7 +271,36 @@ async def create(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
"""
- Create restream
+ Creates a new restream for a specified live stream.
+
+ Specify the target platform's URI (RTMP, RTMPS, or SRT) and the ID of the source
+ stream.
+
+ Restreaming allows you to broadcast a single live stream to multiple platforms
+ or servers simultaneously (e.g., Facebook, YouTube, or a custom media server).
+
+ **How it works:**
+
+ 1. Get credentials (stream URL/key or SRT URL) from the target platform.
+ 2. Create a restream in the Gcore system by specifying the target URI and the
+ source live stream.
+ 3. Start your live stream; it will be automatically pushed to the target
+ destination.
+
+ ```text
+ +-----------------------+
+ RTMP/RTMPS | | --------> Facebook (RTMP)
+ or ------> | Gcore Streaming | --------> YouTube (RTMPS)
+ SRT | | --------> Media server (SRT)
+ +-----------------------+ --------> Other RTMP/SRT targets
+ ```
+
+ **Supported combinations:** RTMP → RTMP, RTMPS → RTMPS, RTMP → SRT, SRT → SRT,
+ SRT → RTMP. For SRT targets, only `mode=caller` is supported (Gcore initiates a
+ PUSH connection).
+
+ Source stream parameters (bitrate, codecs, resolution) are sent "as is". Ensure
+ they match the destination requirements.
Args:
extra_headers: Send extra headers
@@ -277,7 +334,7 @@ async def update(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Restream:
"""
- Updates restream settings
+ Updates restream settings, such as the target URI or active status
Args:
extra_headers: Send extra headers
@@ -308,12 +365,11 @@ def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> AsyncPaginator[Restream, AsyncPageStreaming[Restream]]:
- """Returns a list of created restreams
+ """
+ Returns a list of all restreams created in your account
Args:
- page: Query parameter.
-
- Use it to list the paginated content
+ page: Use it to list the paginated content
extra_headers: Send extra headers
@@ -348,7 +404,7 @@ async def delete(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> None:
"""
- Delete restream
+ Deletes a restream and stops the broadcast to the target destination
Args:
extra_headers: Send extra headers
@@ -380,7 +436,7 @@ async def get(
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> Restream:
"""
- Returns restream details
+ Returns configuration and status details for a specific restream
Args:
extra_headers: Send extra headers
diff --git a/src/gcore/resources/streaming/videos/videos.py b/src/gcore/resources/streaming/videos/videos.py
index 79efd43a..418fc85c 100644
--- a/src/gcore/resources/streaming/videos/videos.py
+++ b/src/gcore/resources/streaming/videos/videos.py
@@ -136,13 +136,14 @@ def create(
**Advanced Features** For details on the requirements for incoming original
files, and output video parameters after transcoding, refer to the Knowledge
- Base documentation. By default video will be transcoded according to the
- original resolution, and a quality ladder suitable for your original video will
- be applied. There is no automatic upscaling; the maximum quality is taken from
- the original video. If you want to upload specific files not explicitly listed
- in requirements or wish to modify the standard quality ladder (i.e. decrease
- quality or add new non-standard qualities), then such customization is possible.
- Please reach out to us for assistance.
+ Base documentation. By default, video will be transcoded into H.264 (AVC)
+ according to the original resolution (up to 4K), and a suitable quality ladder
+ will be applied. More advanced codecs such as HEVC, AV1, and VP9 are available
+ as part of our premium encoding features. There is no automatic upscaling; the
+ maximum quality is taken from the original video. If you want to upload specific
+ files not explicitly listed in requirements or wish to modify the standard
+ quality ladder (i.e. decrease quality or add new non-standard qualities), then
+ such customization is possible. Please reach out to us for assistance.
Additionally, check the Knowledge Base for any supplementary information you may
need.
@@ -883,13 +884,14 @@ async def create(
**Advanced Features** For details on the requirements for incoming original
files, and output video parameters after transcoding, refer to the Knowledge
- Base documentation. By default video will be transcoded according to the
- original resolution, and a quality ladder suitable for your original video will
- be applied. There is no automatic upscaling; the maximum quality is taken from
- the original video. If you want to upload specific files not explicitly listed
- in requirements or wish to modify the standard quality ladder (i.e. decrease
- quality or add new non-standard qualities), then such customization is possible.
- Please reach out to us for assistance.
+ Base documentation. By default, video will be transcoded into H.264 (AVC)
+ according to the original resolution (up to 4K), and a suitable quality ladder
+ will be applied. More advanced codecs such as HEVC, AV1, and VP9 are available
+ as part of our premium encoding features. There is no automatic upscaling; the
+ maximum quality is taken from the original video. If you want to upload specific
+ files not explicitly listed in requirements or wish to modify the standard
+ quality ladder (i.e. decrease quality or add new non-standard qualities), then
+ such customization is possible. Please reach out to us for assistance.
Additionally, check the Knowledge Base for any supplementary information you may
need.
diff --git a/src/gcore/types/streaming/restream.py b/src/gcore/types/streaming/restream.py
index 16800b1d..283f299c 100644
--- a/src/gcore/types/streaming/restream.py
+++ b/src/gcore/types/streaming/restream.py
@@ -34,4 +34,8 @@ class Restream(BaseModel):
"""ID of the stream to restream"""
uri: Optional[str] = None
- """A URL to push the stream to"""
+ """A URL to push the stream to.
+
+ Supported protocols: rtmp, rtmps, srt. For SRT target URLs, only `mode=caller`
+ is supported.
+ """
diff --git a/src/gcore/types/streaming/restream_create_params.py b/src/gcore/types/streaming/restream_create_params.py
index 0d4668e4..6d2c4b37 100644
--- a/src/gcore/types/streaming/restream_create_params.py
+++ b/src/gcore/types/streaming/restream_create_params.py
@@ -38,4 +38,8 @@ class Restream(TypedDict, total=False):
"""ID of the stream to restream"""
uri: str
- """A URL to push the stream to"""
+ """A URL to push the stream to.
+
+ Supported protocols: rtmp, rtmps, srt. For SRT target URLs, only `mode=caller`
+ is supported.
+ """
diff --git a/src/gcore/types/streaming/restream_list_params.py b/src/gcore/types/streaming/restream_list_params.py
index 2cc1b34a..5c78f973 100644
--- a/src/gcore/types/streaming/restream_list_params.py
+++ b/src/gcore/types/streaming/restream_list_params.py
@@ -9,4 +9,4 @@
class RestreamListParams(TypedDict, total=False):
page: int
- """Query parameter. Use it to list the paginated content"""
+ """Use it to list the paginated content"""
diff --git a/src/gcore/types/streaming/restream_update_params.py b/src/gcore/types/streaming/restream_update_params.py
index 9d62d9f7..5303f000 100644
--- a/src/gcore/types/streaming/restream_update_params.py
+++ b/src/gcore/types/streaming/restream_update_params.py
@@ -38,4 +38,8 @@ class Restream(TypedDict, total=False):
"""ID of the stream to restream"""
uri: str
- """A URL to push the stream to"""
+ """A URL to push the stream to.
+
+ Supported protocols: rtmp, rtmps, srt. For SRT target URLs, only `mode=caller`
+ is supported.
+ """
From 2fbb1d4841153fb0906e30ca3ccd4047a51f9e55 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 8 May 2026 08:26:27 +0000
Subject: [PATCH 08/12] chore(client): rename cloud_polling_* opts to polling_*
---
.stats.yml | 4 ++--
src/gcore/_client.py | 56 ++++++++++++++++++++++----------------------
2 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index 93dd0f0c..356d6c63 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 655
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-654176da11454546a55cd34a004f89ee9133d144f2f3d6f1b23701e85d645fb8.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-a75fe919f707b72deefe3d4fd7318b73b6cb6ab7305dcda67b9c72cb6cfd5325.yml
openapi_spec_hash: a96c0414ee2343a62ea3e4938bbccbd0
-config_hash: 88e4af508ede520a45a0563d9cf077cc
+config_hash: 3d00790fb3a2bad4e5d5eb2e02645385
diff --git a/src/gcore/_client.py b/src/gcore/_client.py
index de48ead3..067b2fe1 100644
--- a/src/gcore/_client.py
+++ b/src/gcore/_client.py
@@ -55,8 +55,8 @@ class Gcore(SyncAPIClient):
api_key: str
cloud_project_id: int | None
cloud_region_id: int | None
- cloud_polling_interval_seconds: int | None
- cloud_polling_timeout_seconds: int | None
+ polling_interval_seconds: int | None
+ polling_timeout_seconds: int | None
def __init__(
self,
@@ -64,8 +64,8 @@ def __init__(
api_key: str | None = None,
cloud_project_id: int | None = None,
cloud_region_id: int | None = None,
- cloud_polling_interval_seconds: int | None = 3,
- cloud_polling_timeout_seconds: int | None = 7200,
+ polling_interval_seconds: int | None = 3,
+ polling_timeout_seconds: int | None = 7200,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -108,13 +108,13 @@ def __init__(
cloud_region_id = maybe_coerce_integer(os.environ.get("GCORE_CLOUD_REGION_ID"))
self.cloud_region_id = cloud_region_id
- if cloud_polling_interval_seconds is None:
- cloud_polling_interval_seconds = 3
- self.cloud_polling_interval_seconds = cloud_polling_interval_seconds
+ if polling_interval_seconds is None:
+ polling_interval_seconds = 3
+ self.polling_interval_seconds = polling_interval_seconds
- if cloud_polling_timeout_seconds is None:
- cloud_polling_timeout_seconds = 7200
- self.cloud_polling_timeout_seconds = cloud_polling_timeout_seconds
+ if polling_timeout_seconds is None:
+ polling_timeout_seconds = 7200
+ self.polling_timeout_seconds = polling_timeout_seconds
if base_url is None:
base_url = os.environ.get("GCORE_BASE_URL")
@@ -233,8 +233,8 @@ def copy(
api_key: str | None = None,
cloud_project_id: int | None = None,
cloud_region_id: int | None = None,
- cloud_polling_interval_seconds: int | None = None,
- cloud_polling_timeout_seconds: int | None = None,
+ polling_interval_seconds: int | None = None,
+ polling_timeout_seconds: int | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
http_client: httpx.Client | None = None,
@@ -271,8 +271,8 @@ def copy(
api_key=api_key or self.api_key,
cloud_project_id=cloud_project_id or self.cloud_project_id,
cloud_region_id=cloud_region_id or self.cloud_region_id,
- cloud_polling_interval_seconds=cloud_polling_interval_seconds or self.cloud_polling_interval_seconds,
- cloud_polling_timeout_seconds=cloud_polling_timeout_seconds or self.cloud_polling_timeout_seconds,
+ polling_interval_seconds=polling_interval_seconds or self.polling_interval_seconds,
+ polling_timeout_seconds=polling_timeout_seconds or self.polling_timeout_seconds,
base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
http_client=http_client,
@@ -343,8 +343,8 @@ class AsyncGcore(AsyncAPIClient):
api_key: str
cloud_project_id: int | None
cloud_region_id: int | None
- cloud_polling_interval_seconds: int | None
- cloud_polling_timeout_seconds: int | None
+ polling_interval_seconds: int | None
+ polling_timeout_seconds: int | None
def __init__(
self,
@@ -352,8 +352,8 @@ def __init__(
api_key: str | None = None,
cloud_project_id: int | None = None,
cloud_region_id: int | None = None,
- cloud_polling_interval_seconds: int | None = 3,
- cloud_polling_timeout_seconds: int | None = 7200,
+ polling_interval_seconds: int | None = 3,
+ polling_timeout_seconds: int | None = 7200,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -396,13 +396,13 @@ def __init__(
cloud_region_id = maybe_coerce_integer(os.environ.get("GCORE_CLOUD_REGION_ID"))
self.cloud_region_id = cloud_region_id
- if cloud_polling_interval_seconds is None:
- cloud_polling_interval_seconds = 3
- self.cloud_polling_interval_seconds = cloud_polling_interval_seconds
+ if polling_interval_seconds is None:
+ polling_interval_seconds = 3
+ self.polling_interval_seconds = polling_interval_seconds
- if cloud_polling_timeout_seconds is None:
- cloud_polling_timeout_seconds = 7200
- self.cloud_polling_timeout_seconds = cloud_polling_timeout_seconds
+ if polling_timeout_seconds is None:
+ polling_timeout_seconds = 7200
+ self.polling_timeout_seconds = polling_timeout_seconds
if base_url is None:
base_url = os.environ.get("GCORE_BASE_URL")
@@ -521,8 +521,8 @@ def copy(
api_key: str | None = None,
cloud_project_id: int | None = None,
cloud_region_id: int | None = None,
- cloud_polling_interval_seconds: int | None = None,
- cloud_polling_timeout_seconds: int | None = None,
+ polling_interval_seconds: int | None = None,
+ polling_timeout_seconds: int | None = None,
base_url: str | httpx.URL | None = None,
timeout: float | Timeout | None | NotGiven = not_given,
http_client: httpx.AsyncClient | None = None,
@@ -559,8 +559,8 @@ def copy(
api_key=api_key or self.api_key,
cloud_project_id=cloud_project_id or self.cloud_project_id,
cloud_region_id=cloud_region_id or self.cloud_region_id,
- cloud_polling_interval_seconds=cloud_polling_interval_seconds or self.cloud_polling_interval_seconds,
- cloud_polling_timeout_seconds=cloud_polling_timeout_seconds or self.cloud_polling_timeout_seconds,
+ polling_interval_seconds=polling_interval_seconds or self.polling_interval_seconds,
+ polling_timeout_seconds=polling_timeout_seconds or self.polling_timeout_seconds,
base_url=base_url or self.base_url,
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
http_client=http_client,
From dd6eaa95eb50cfb5e8fb14938062d406851e16c5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 8 May 2026 10:08:35 +0000
Subject: [PATCH 09/12] feat(cdn): add client_config SDK subresource for
/cdn/clients/me
---
.stats.yml | 4 +-
src/gcore/resources/cdn/__init__.py | 14 ++
src/gcore/resources/cdn/api.md | 6 +
src/gcore/resources/cdn/cdn.py | 38 +++++
src/gcore/resources/cdn/client_config.py | 139 ++++++++++++++++++
tests/api_resources/cdn/test_client_config.py | 74 ++++++++++
6 files changed, 273 insertions(+), 2 deletions(-)
create mode 100644 src/gcore/resources/cdn/client_config.py
create mode 100644 tests/api_resources/cdn/test_client_config.py
diff --git a/.stats.yml b/.stats.yml
index 356d6c63..ee5fa6a0 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 655
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-a75fe919f707b72deefe3d4fd7318b73b6cb6ab7305dcda67b9c72cb6cfd5325.yml
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-5557f17488082c54f75ee595867c4d9789c5b8aa4cd15b8057c22e1e0af7bc24.yml
openapi_spec_hash: a96c0414ee2343a62ea3e4938bbccbd0
-config_hash: 3d00790fb3a2bad4e5d5eb2e02645385
+config_hash: 24d55cb26d543a2d65d129ebe46f7775
diff --git a/src/gcore/resources/cdn/__init__.py b/src/gcore/resources/cdn/__init__.py
index 4347554b..ec1fa10f 100644
--- a/src/gcore/resources/cdn/__init__.py
+++ b/src/gcore/resources/cdn/__init__.py
@@ -80,6 +80,14 @@
CDNResourcesResourceWithStreamingResponse,
AsyncCDNResourcesResourceWithStreamingResponse,
)
+from .client_config import (
+ ClientConfigResource,
+ AsyncClientConfigResource,
+ ClientConfigResourceWithRawResponse,
+ AsyncClientConfigResourceWithRawResponse,
+ ClientConfigResourceWithStreamingResponse,
+ AsyncClientConfigResourceWithStreamingResponse,
+)
from .logs_uploader import (
LogsUploaderResource,
AsyncLogsUploaderResource,
@@ -206,6 +214,12 @@
"AsyncIPsResourceWithRawResponse",
"IPsResourceWithStreamingResponse",
"AsyncIPsResourceWithStreamingResponse",
+ "ClientConfigResource",
+ "AsyncClientConfigResource",
+ "ClientConfigResourceWithRawResponse",
+ "AsyncClientConfigResourceWithRawResponse",
+ "ClientConfigResourceWithStreamingResponse",
+ "AsyncClientConfigResourceWithStreamingResponse",
"CDNResource",
"AsyncCDNResource",
"CDNResourceWithRawResponse",
diff --git a/src/gcore/resources/cdn/api.md b/src/gcore/resources/cdn/api.md
index 002855e7..054a130d 100644
--- a/src/gcore/resources/cdn/api.md
+++ b/src/gcore/resources/cdn/api.md
@@ -317,3 +317,9 @@ from gcore.types.cdn import PublicIPList
Methods:
- client.cdn.ips.list(\*\*params) -> PublicIPList
+
+## ClientConfig
+
+Methods:
+
+- client.cdn.client_config.get() -> CDNAccount
diff --git a/src/gcore/resources/cdn/cdn.py b/src/gcore/resources/cdn/cdn.py
index 0419323c..986248e7 100644
--- a/src/gcore/resources/cdn/cdn.py
+++ b/src/gcore/resources/cdn/cdn.py
@@ -86,6 +86,14 @@
CertificatesResourceWithStreamingResponse,
AsyncCertificatesResourceWithStreamingResponse,
)
+from .client_config import (
+ ClientConfigResource,
+ AsyncClientConfigResource,
+ ClientConfigResourceWithRawResponse,
+ AsyncClientConfigResourceWithRawResponse,
+ ClientConfigResourceWithStreamingResponse,
+ AsyncClientConfigResourceWithStreamingResponse,
+)
from .origin_groups import (
OriginGroupsResource,
AsyncOriginGroupsResource,
@@ -242,6 +250,11 @@ def ip_ranges(self) -> IPRangesResource:
def ips(self) -> IPsResource:
return IPsResource(self._client)
+ @cached_property
+ def client_config(self) -> ClientConfigResource:
+ """Information about the current state of the CDN service in your account."""
+ return ClientConfigResource(self._client)
+
@cached_property
def with_raw_response(self) -> CDNResourceWithRawResponse:
"""
@@ -652,6 +665,11 @@ def ip_ranges(self) -> AsyncIPRangesResource:
def ips(self) -> AsyncIPsResource:
return AsyncIPsResource(self._client)
+ @cached_property
+ def client_config(self) -> AsyncClientConfigResource:
+ """Information about the current state of the CDN service in your account."""
+ return AsyncClientConfigResource(self._client)
+
@cached_property
def with_raw_response(self) -> AsyncCDNResourceWithRawResponse:
"""
@@ -1087,6 +1105,11 @@ def ip_ranges(self) -> IPRangesResourceWithRawResponse:
def ips(self) -> IPsResourceWithRawResponse:
return IPsResourceWithRawResponse(self._cdn.ips)
+ @cached_property
+ def client_config(self) -> ClientConfigResourceWithRawResponse:
+ """Information about the current state of the CDN service in your account."""
+ return ClientConfigResourceWithRawResponse(self._cdn.client_config)
+
class AsyncCDNResourceWithRawResponse:
def __init__(self, cdn: AsyncCDNResource) -> None:
@@ -1210,6 +1233,11 @@ def ip_ranges(self) -> AsyncIPRangesResourceWithRawResponse:
def ips(self) -> AsyncIPsResourceWithRawResponse:
return AsyncIPsResourceWithRawResponse(self._cdn.ips)
+ @cached_property
+ def client_config(self) -> AsyncClientConfigResourceWithRawResponse:
+ """Information about the current state of the CDN service in your account."""
+ return AsyncClientConfigResourceWithRawResponse(self._cdn.client_config)
+
class CDNResourceWithStreamingResponse:
def __init__(self, cdn: CDNResource) -> None:
@@ -1333,6 +1361,11 @@ def ip_ranges(self) -> IPRangesResourceWithStreamingResponse:
def ips(self) -> IPsResourceWithStreamingResponse:
return IPsResourceWithStreamingResponse(self._cdn.ips)
+ @cached_property
+ def client_config(self) -> ClientConfigResourceWithStreamingResponse:
+ """Information about the current state of the CDN service in your account."""
+ return ClientConfigResourceWithStreamingResponse(self._cdn.client_config)
+
class AsyncCDNResourceWithStreamingResponse:
def __init__(self, cdn: AsyncCDNResource) -> None:
@@ -1455,3 +1488,8 @@ def ip_ranges(self) -> AsyncIPRangesResourceWithStreamingResponse:
@cached_property
def ips(self) -> AsyncIPsResourceWithStreamingResponse:
return AsyncIPsResourceWithStreamingResponse(self._cdn.ips)
+
+ @cached_property
+ def client_config(self) -> AsyncClientConfigResourceWithStreamingResponse:
+ """Information about the current state of the CDN service in your account."""
+ return AsyncClientConfigResourceWithStreamingResponse(self._cdn.client_config)
diff --git a/src/gcore/resources/cdn/client_config.py b/src/gcore/resources/cdn/client_config.py
new file mode 100644
index 00000000..d026cb21
--- /dev/null
+++ b/src/gcore/resources/cdn/client_config.py
@@ -0,0 +1,139 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..._types import Body, Query, Headers, NotGiven, not_given
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..._base_client import make_request_options
+from ...types.cdn.cdn_account import CDNAccount
+
+__all__ = ["ClientConfigResource", "AsyncClientConfigResource"]
+
+
+class ClientConfigResource(SyncAPIResource):
+ """Information about the current state of the CDN service in your account."""
+
+ @cached_property
+ def with_raw_response(self) -> ClientConfigResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return ClientConfigResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ClientConfigResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return ClientConfigResourceWithStreamingResponse(self)
+
+ def get(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CDNAccount:
+ """Get information about CDN service."""
+ return self._get(
+ "/cdn/clients/me",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CDNAccount,
+ )
+
+
+class AsyncClientConfigResource(AsyncAPIResource):
+ """Information about the current state of the CDN service in your account."""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncClientConfigResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncClientConfigResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncClientConfigResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/G-Core/gcore-python#with_streaming_response
+ """
+ return AsyncClientConfigResourceWithStreamingResponse(self)
+
+ async def get(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> CDNAccount:
+ """Get information about CDN service."""
+ return await self._get(
+ "/cdn/clients/me",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CDNAccount,
+ )
+
+
+class ClientConfigResourceWithRawResponse:
+ def __init__(self, client_config: ClientConfigResource) -> None:
+ self._client_config = client_config
+
+ self.get = to_raw_response_wrapper(
+ client_config.get,
+ )
+
+
+class AsyncClientConfigResourceWithRawResponse:
+ def __init__(self, client_config: AsyncClientConfigResource) -> None:
+ self._client_config = client_config
+
+ self.get = async_to_raw_response_wrapper(
+ client_config.get,
+ )
+
+
+class ClientConfigResourceWithStreamingResponse:
+ def __init__(self, client_config: ClientConfigResource) -> None:
+ self._client_config = client_config
+
+ self.get = to_streamed_response_wrapper(
+ client_config.get,
+ )
+
+
+class AsyncClientConfigResourceWithStreamingResponse:
+ def __init__(self, client_config: AsyncClientConfigResource) -> None:
+ self._client_config = client_config
+
+ self.get = async_to_streamed_response_wrapper(
+ client_config.get,
+ )
diff --git a/tests/api_resources/cdn/test_client_config.py b/tests/api_resources/cdn/test_client_config.py
new file mode 100644
index 00000000..c712d6a6
--- /dev/null
+++ b/tests/api_resources/cdn/test_client_config.py
@@ -0,0 +1,74 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from gcore import Gcore, AsyncGcore
+from tests.utils import assert_matches_type
+from gcore.types.cdn import CDNAccount
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestClientConfig:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_get(self, client: Gcore) -> None:
+ client_config = client.cdn.client_config.get()
+ assert_matches_type(CDNAccount, client_config, path=["response"])
+
+ @parametrize
+ def test_raw_response_get(self, client: Gcore) -> None:
+ response = client.cdn.client_config.with_raw_response.get()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ client_config = response.parse()
+ assert_matches_type(CDNAccount, client_config, path=["response"])
+
+ @parametrize
+ def test_streaming_response_get(self, client: Gcore) -> None:
+ with client.cdn.client_config.with_streaming_response.get() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ client_config = response.parse()
+ assert_matches_type(CDNAccount, client_config, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncClientConfig:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_get(self, async_client: AsyncGcore) -> None:
+ client_config = await async_client.cdn.client_config.get()
+ assert_matches_type(CDNAccount, client_config, path=["response"])
+
+ @parametrize
+ async def test_raw_response_get(self, async_client: AsyncGcore) -> None:
+ response = await async_client.cdn.client_config.with_raw_response.get()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ client_config = await response.parse()
+ assert_matches_type(CDNAccount, client_config, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_get(self, async_client: AsyncGcore) -> None:
+ async with async_client.cdn.client_config.with_streaming_response.get() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ client_config = await response.parse()
+ assert_matches_type(CDNAccount, client_config, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
From 362e10e9e0ddf616b0cef38c71ae05bbf90124f5 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 8 May 2026 12:17:14 +0000
Subject: [PATCH 10/12] codegen metadata
---
.stats.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.stats.yml b/.stats.yml
index ee5fa6a0..13b6f227 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
configured_endpoints: 655
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-5557f17488082c54f75ee595867c4d9789c5b8aa4cd15b8057c22e1e0af7bc24.yml
-openapi_spec_hash: a96c0414ee2343a62ea3e4938bbccbd0
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-ca11e3a3caab61a2583bde810437de01f0635c3a48b7eceb20f910701452bc56.yml
+openapi_spec_hash: eba662f80750410bacdbe0bcf4b8d875
config_hash: 24d55cb26d543a2d65d129ebe46f7775
From dcc262a3bd776078d57aa27b484b7f3982b68861 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 8 May 2026 17:14:27 +0000
Subject: [PATCH 11/12] fix(client): add missing f-string prefix in file type
error message
---
src/gcore/_files.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/gcore/_files.py b/src/gcore/_files.py
index 0fdce17b..76da9e08 100644
--- a/src/gcore/_files.py
+++ b/src/gcore/_files.py
@@ -99,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles
elif is_sequence_t(files):
files = [(key, await _async_transform_file(file)) for key, file in files]
else:
- raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence")
+ raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence")
return files
From f05e50f57202e215bd827e038ffbf3843da4a43d Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 8 May 2026 17:15:06 +0000
Subject: [PATCH 12/12] release: 0.46.0
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 23 +++++++++++++++++++++++
pyproject.toml | 2 +-
src/gcore/_version.py | 2 +-
4 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index fc0d7ff8..563004f2 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.45.0"
+ ".": "0.46.0"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1618ea7e..6dcce1fc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,28 @@
# Changelog
+## 0.46.0 (2026-05-08)
+
+Full Changelog: [v0.45.0...v0.46.0](https://github.com/G-Core/gcore-python/compare/v0.45.0...v0.46.0)
+
+### Features
+
+* add cross-SDK sync and relax CI breaking-change check for /release skill ([227d229](https://github.com/G-Core/gcore-python/commit/227d229251317cfa2e9cc57d55e28f6bf85c6a7a))
+* **api:** aggregated API specs update ([9d56917](https://github.com/G-Core/gcore-python/commit/9d56917be59224908e9953809511d9132a4a899b))
+* **api:** aggregated API specs update ([6722396](https://github.com/G-Core/gcore-python/commit/6722396ffbc3a6d73433b6393e7f5e812d0de4f2))
+* **api:** aggregated API specs update ([f5efa16](https://github.com/G-Core/gcore-python/commit/f5efa161e613f3dd5b9078edf87b1ff09c6d990b))
+* **api:** aggregated API specs update ([adc6730](https://github.com/G-Core/gcore-python/commit/adc67307096350666c53204150fbb30a14cb9a7e))
+* **cdn:** add client_config SDK subresource for /cdn/clients/me ([dd6eaa9](https://github.com/G-Core/gcore-python/commit/dd6eaa95eb50cfb5e8fb14938062d406851e16c5))
+
+
+### Bug Fixes
+
+* **client:** add missing f-string prefix in file type error message ([dcc262a](https://github.com/G-Core/gcore-python/commit/dcc262a3bd776078d57aa27b484b7f3982b68861))
+
+
+### Chores
+
+* **client:** rename cloud_polling_* opts to polling_* ([2fbb1d4](https://github.com/G-Core/gcore-python/commit/2fbb1d4841153fb0906e30ca3ccd4047a51f9e55))
+
## 0.45.0 (2026-05-04)
Full Changelog: [v0.44.0...v0.45.0](https://github.com/G-Core/gcore-python/compare/v0.44.0...v0.45.0)
diff --git a/pyproject.toml b/pyproject.toml
index 3cb70b03..970a913f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "gcore"
-version = "0.45.0"
+version = "0.46.0"
description = "The official Python library for the gcore API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/gcore/_version.py b/src/gcore/_version.py
index a2c340f2..734f3574 100644
--- a/src/gcore/_version.py
+++ b/src/gcore/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "gcore"
-__version__ = "0.45.0" # x-release-please-version
+__version__ = "0.46.0" # x-release-please-version