diff --git a/.agents/skills/release/SKILL.md b/.agents/skills/release/SKILL.md index e956f2d64..0e296f49b 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` | diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fc0d7ff8b..563004f25 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/.stats.yml b/.stats.yml index daa2a1295..13b6f2273 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 -config_hash: 88e4af508ede520a45a0563d9cf077cc +configured_endpoints: 655 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gcore/gcore-ca11e3a3caab61a2583bde810437de01f0635c3a48b7eceb20f910701452bc56.yml +openapi_spec_hash: eba662f80750410bacdbe0bcf4b8d875 +config_hash: 24d55cb26d543a2d65d129ebe46f7775 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1618ea7e8..6dcce1fcb 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 3cb70b034..970a913f0 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/_client.py b/src/gcore/_client.py index de48ead3b..067b2fe1f 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, diff --git a/src/gcore/_files.py b/src/gcore/_files.py index 0fdce17bf..76da9e085 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 diff --git a/src/gcore/_version.py b/src/gcore/_version.py index a2c340f23..734f35742 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 diff --git a/src/gcore/resources/cdn/__init__.py b/src/gcore/resources/cdn/__init__.py index 4347554b1..ec1fa10f7 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 002855e7a..054a130dd 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 0419323ca..986248e72 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 000000000..d026cb214 --- /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/src/gcore/resources/storage/api.md b/src/gcore/resources/storage/api.md index a3a72e3e9..b3a82664b 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 f29a71c35..7e48c9ec2 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/resources/streaming/quality_sets.py b/src/gcore/resources/streaming/quality_sets.py index 4aff78433..121f80d16 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 d38b2183f..1f27e9874 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 79efd43ae..418fc85c3 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/resources/waap/analytics.py b/src/gcore/resources/waap/analytics.py index a0a8389f0..0ce5c2527 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/cdn/origin_group_create_params.py b/src/gcore/types/cdn/origin_group_create_params.py index 8efbd7d26..4620451e7 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 a8694a660..4dac9f00a 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 63a0cb0fa..57731be13 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 43a63d92e..c1b7e915c 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): diff --git a/src/gcore/types/storage/object_storages/__init__.py b/src/gcore/types/storage/object_storages/__init__.py index 5bce0f48d..9e6aa5071 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 75b029279..000000000 --- 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/src/gcore/types/streaming/restream.py b/src/gcore/types/streaming/restream.py index 16800b1da..283f299c3 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 0d4668e46..6d2c4b371 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 2cc1b34a8..5c78f9731 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 9d62d9f77..5303f000d 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. + """ diff --git a/src/gcore/types/waap/analytics_get_requests_params.py b/src/gcore/types/waap/analytics_get_requests_params.py index 361e70ce4..623a01210 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 211e14465..15ed0dda1 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 16475cd97..c44f44747 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 22be6abaa..89250e5ec 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/cdn/test_client_config.py b/tests/api_resources/cdn/test_client_config.py new file mode 100644 index 000000000..c712d6a65 --- /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 diff --git a/tests/api_resources/storage/object_storages/test_buckets.py b/tests/api_resources/storage/object_storages/test_buckets.py index 5bae6c0e5..5f9c13255 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, - ) diff --git a/tests/api_resources/waap/test_analytics.py b/tests/api_resources/waap/test_analytics.py index adae66f57..d46210a4e 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"])