diff --git a/.release-please-manifest.json b/.release-please-manifest.json index aa39267a..0d51a367 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.76.0" + ".": "0.78.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 3f7dec3b..04d533eb 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 125 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-ba32039d3975da7aa6d28e5184f0a44c9fbfe36ab7dbc71985d14e2ecc0867b9.yml -openapi_spec_hash: a9f32fc90c2add2ae85af828c298e35b -config_hash: 06186eb40e0058a2a87ac251fc07415d +configured_endpoints: 127 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel/kernel-1413d61d06059008b4c1e204c783d8b2e7dca9af23f6e3b6d2552493ea2d9853.yml +openapi_spec_hash: 80aca500caddd300cb03a6daf568fddb +config_hash: 77ee715aa17061166f9a02b264a21b8d diff --git a/CHANGELOG.md b/CHANGELOG.md index e0c979f6..f8ef4df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## 0.78.0 (2026-07-13) + +Full Changelog: [v0.76.0...v0.78.0](https://github.com/kernel/kernel-python-sdk/compare/v0.76.0...v0.78.0) + +### Features + +* Add exact-match name filter to list endpoints ([6011556](https://github.com/kernel/kernel-python-sdk/commit/601155642a4d082d19c3b3293eea6d6105f74407)) +* Add name-only rename for profiles and proxies ([1d38266](https://github.com/kernel/kernel-python-sdk/commit/1d3826696cb2005ab6c33a7cd1df19b660d66449)) +* Auto-default refresh_on_profile_update when browser pool profile changes ([4771197](https://github.com/kernel/kernel-python-sdk/commit/4771197c55a1562d465f9b75d8a8e2a12f5e6f76)) +* Document name uniqueness and query match semantics ([e27f37d](https://github.com/kernel/kernel-python-sdk/commit/e27f37d43b1d76628c42f90e77a18af513c86280)) +* Expose telemetry exception message in API/SDK ([6575dd2](https://github.com/kernel/kernel-python-sdk/commit/6575dd21919b092a77de88e4ee8d037f601edadc)) +* Make the browser pool OpenAPI contract truthful ([20b3a7e](https://github.com/kernel/kernel-python-sdk/commit/20b3a7efc61b7de4007fdd9d096595bfab9c06c3)) +* Persist and echo deployment source identity ([5db2b01](https://github.com/kernel/kernel-python-sdk/commit/5db2b01c8ad53441cb3cc7056b8b4b7c8cbcc45c)) +* Support multiple audit log method exclusions ([f9decdd](https://github.com/kernel/kernel-python-sdk/commit/f9decdd9d2f617c4483d3a5ddd568f34ac8052f6)) + + +### Documentation + +* **openapi:** describe unified concurrency limit, deprecate max_pooled_sessions (CUS-275) ([8c85318](https://github.com/kernel/kernel-python-sdk/commit/8c85318da7d5b064b867b1e4d029937eafc08d13)) + ## 0.76.0 (2026-07-09) Full Changelog: [v0.75.0...v0.76.0](https://github.com/kernel/kernel-python-sdk/compare/v0.75.0...v0.76.0) diff --git a/api.md b/api.md index 300e937b..7feea4cd 100644 --- a/api.md +++ b/api.md @@ -285,6 +285,7 @@ Methods: - client.profiles.create(\*\*params) -> Profile - client.profiles.retrieve(id_or_name) -> Profile +- client.profiles.update(id_or_name, \*\*params) -> Profile - client.profiles.list(\*\*params) -> SyncOffsetPagination[Profile] - client.profiles.delete(id_or_name) -> None - client.profiles.download(id_or_name) -> BinaryAPIResponse @@ -328,6 +329,7 @@ Types: from kernel.types import ( ProxyCreateResponse, ProxyRetrieveResponse, + ProxyUpdateResponse, ProxyListResponse, ProxyCheckResponse, ) @@ -337,6 +339,7 @@ Methods: - client.proxies.create(\*\*params) -> ProxyCreateResponse - client.proxies.retrieve(id) -> ProxyRetrieveResponse +- client.proxies.update(id, \*\*params) -> ProxyUpdateResponse - client.proxies.list(\*\*params) -> SyncOffsetPagination[ProxyListResponse] - client.proxies.delete(id) -> None - client.proxies.check(id, \*\*params) -> ProxyCheckResponse diff --git a/pyproject.toml b/pyproject.toml index 205c9767..d2f34d9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.76.0" +version = "0.78.0" description = "The official Python library for the kernel API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/kernel/_version.py b/src/kernel/_version.py index 443b322f..e90c0a29 100644 --- a/src/kernel/_version.py +++ b/src/kernel/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "kernel" -__version__ = "0.76.0" # x-release-please-version +__version__ = "0.78.0" # x-release-please-version diff --git a/src/kernel/resources/api_keys.py b/src/kernel/resources/api_keys.py index 502e8897..8cc1ed53 100644 --- a/src/kernel/resources/api_keys.py +++ b/src/kernel/resources/api_keys.py @@ -71,7 +71,7 @@ def create( Create a new API key within the authenticated organization. Args: - name: API key name (1-255 characters) + name: Label for the API key (1-255 characters). API keys are not addressable by name. days_to_expire: Number of days until expiry, up to 3650. Use null for never. @@ -188,6 +188,7 @@ def list( *, include_deleted: bool | Omit = omit, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, sort_by: Literal["created_at", "name", "expires_at"] | Omit = omit, @@ -210,6 +211,11 @@ def list( limit: Maximum number of results to return + name: Exact-match filter on API key name using the database collation. In production, + matching is case- and accent-insensitive. Names are not required to be unique, + so multiple keys may match. When status=all or include_deleted=true is set, + soft-deleted keys with the same name may also match. + offset: Number of results to skip query: Case-insensitive substring match against API key name, creator, and project. API @@ -243,6 +249,7 @@ def list( { "include_deleted": include_deleted, "limit": limit, + "name": name, "offset": offset, "query": query, "sort_by": sort_by, @@ -382,7 +389,7 @@ async def create( Create a new API key within the authenticated organization. Args: - name: API key name (1-255 characters) + name: Label for the API key (1-255 characters). API keys are not addressable by name. days_to_expire: Number of days until expiry, up to 3650. Use null for never. @@ -499,6 +506,7 @@ def list( *, include_deleted: bool | Omit = omit, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, sort_by: Literal["created_at", "name", "expires_at"] | Omit = omit, @@ -521,6 +529,11 @@ def list( limit: Maximum number of results to return + name: Exact-match filter on API key name using the database collation. In production, + matching is case- and accent-insensitive. Names are not required to be unique, + so multiple keys may match. When status=all or include_deleted=true is set, + soft-deleted keys with the same name may also match. + offset: Number of results to skip query: Case-insensitive substring match against API key name, creator, and project. API @@ -554,6 +567,7 @@ def list( { "include_deleted": include_deleted, "limit": limit, + "name": name, "offset": offset, "query": query, "sort_by": sort_by, diff --git a/src/kernel/resources/audit_logs.py b/src/kernel/resources/audit_logs.py index 814db9c7..2970e153 100644 --- a/src/kernel/resources/audit_logs.py +++ b/src/kernel/resources/audit_logs.py @@ -62,7 +62,7 @@ def list( end: Union[str, datetime], start: Union[str, datetime], auth_strategy: str | Omit = omit, - exclude_method: str | Omit = omit, + exclude_method: SequenceNotStr[str] | Omit = omit, limit: int | Omit = omit, method: str | Omit = omit, page_token: str | Omit = omit, @@ -144,7 +144,7 @@ def export_chunk( start: Union[str, datetime], auth_strategy: str | Omit = omit, cursor: str | Omit = omit, - exclude_method: str | Omit = omit, + exclude_method: SequenceNotStr[str] | Omit = omit, format: Literal["jsonl", "jsonl.gz"] | Omit = omit, limit: int | Omit = omit, method: str | Omit = omit, @@ -251,7 +251,7 @@ def list( end: Union[str, datetime], start: Union[str, datetime], auth_strategy: str | Omit = omit, - exclude_method: str | Omit = omit, + exclude_method: SequenceNotStr[str] | Omit = omit, limit: int | Omit = omit, method: str | Omit = omit, page_token: str | Omit = omit, @@ -333,7 +333,7 @@ async def export_chunk( start: Union[str, datetime], auth_strategy: str | Omit = omit, cursor: str | Omit = omit, - exclude_method: str | Omit = omit, + exclude_method: SequenceNotStr[str] | Omit = omit, format: Literal["jsonl", "jsonl.gz"] | Omit = omit, limit: int | Omit = omit, method: str | Omit = omit, diff --git a/src/kernel/resources/auth/connections.py b/src/kernel/resources/auth/connections.py index 24a560c2..30f8dca8 100644 --- a/src/kernel/resources/auth/connections.py +++ b/src/kernel/resources/auth/connections.py @@ -140,7 +140,9 @@ def create( login_url: Optional login page URL to skip discovery proxy: Proxy selection. Provide either id or name. The proxy must be in the same - project as the resource referencing it. + project as the resource referencing it. When selecting by name, the name must + match exactly one active proxy in the project. Ambiguous names return a 400; use + id for stable references. record_session: Whether to record browser sessions for this connection by default. Useful for debugging. Can be overridden per-login. Defaults to false. @@ -268,7 +270,9 @@ def update( login_url: Login page URL. Set to empty string to clear. proxy: Proxy selection. Provide either id or name. The proxy must be in the same - project as the resource referencing it. + project as the resource referencing it. When selecting by name, the name must + match exactly one active proxy in the project. Ambiguous names return a 400; use + id for stable references. record_session: Whether to record browser sessions for this connection by default @@ -465,7 +469,9 @@ def login( Args: proxy: Proxy selection. Provide either id or name. The proxy must be in the same - project as the resource referencing it. + project as the resource referencing it. When selecting by name, the name must + match exactly one active proxy in the project. Ambiguous names return a 400; use + id for stable references. record_session: Override the connection's default for recording this login's browser session. When omitted, the connection's record_session default is used. @@ -717,7 +723,9 @@ async def create( login_url: Optional login page URL to skip discovery proxy: Proxy selection. Provide either id or name. The proxy must be in the same - project as the resource referencing it. + project as the resource referencing it. When selecting by name, the name must + match exactly one active proxy in the project. Ambiguous names return a 400; use + id for stable references. record_session: Whether to record browser sessions for this connection by default. Useful for debugging. Can be overridden per-login. Defaults to false. @@ -845,7 +853,9 @@ async def update( login_url: Login page URL. Set to empty string to clear. proxy: Proxy selection. Provide either id or name. The proxy must be in the same - project as the resource referencing it. + project as the resource referencing it. When selecting by name, the name must + match exactly one active proxy in the project. Ambiguous names return a 400; use + id for stable references. record_session: Whether to record browser sessions for this connection by default @@ -1042,7 +1052,9 @@ async def login( Args: proxy: Proxy selection. Provide either id or name. The proxy must be in the same - project as the resource referencing it. + project as the resource referencing it. When selecting by name, the name must + match exactly one active proxy in the project. Ambiguous names return a 400; use + id for stable references. record_session: Override the connection's default for recording this login's browser session. When omitted, the connection's record_session default is used. diff --git a/src/kernel/resources/browser_pools.py b/src/kernel/resources/browser_pools.py index 12239d00..5810f332 100644 --- a/src/kernel/resources/browser_pools.py +++ b/src/kernel/resources/browser_pools.py @@ -96,7 +96,8 @@ def create( chrome_policy: Custom Chrome enterprise policy overrides applied to all browsers in this pool. Keys are Chrome enterprise policy names; values must match their expected types. Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See - https://chromeenterprise.google/policies/ + https://chromeenterprise.google/policies/ The serialized JSON payload is capped + at 5 MiB. extensions: List of browser extensions to load into the session. Provide each by id or name. @@ -107,7 +108,7 @@ def create( headless: If true, launches the browser using a headless image. Defaults to false. kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live - view. + view. Defaults to false. name: Optional name for the browser pool. Must be unique within the project. @@ -121,8 +122,8 @@ def create( the same project as the browser session. refresh_on_profile_update: When true, flush idle browsers when the profile the pool uses is updated, so - pool browsers pick up the latest profile data. Requires a profile to be set on - the pool. + pool browsers pick up the latest profile data. When a profile is provided during + creation, this defaults to true. Requires a profile to be set on the pool. start_url: Optional URL to navigate to when a new browser is warmed into the pool. Best-effort: failures to navigate do not fail pool fill. Only applied to @@ -131,7 +132,7 @@ def create( chrome:// pages. stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot - mechanisms. + mechanisms. Defaults to false. timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they are destroyed. Defaults to 600 seconds. Minimum 10, maximum 259200 (72 hours). @@ -252,10 +253,12 @@ def update( `refresh_on_profile_update`. Args: - chrome_policy: Custom Chrome enterprise policy overrides applied to all browsers in this pool. - Keys are Chrome enterprise policy names; values must match their expected types. + chrome_policy: If provided, replaces the custom Chrome enterprise policy overrides applied to + all browsers in this pool. Empty object clears any previously-set policy. Keys + are Chrome enterprise policy names; values must match their expected types. Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See - https://chromeenterprise.google/policies/ + https://chromeenterprise.google/policies/ The serialized JSON payload is capped + at 5 MiB. discard_all_idle: Whether to discard all idle browsers and rebuild them immediately with the new configuration. Defaults to false. Only browsers that are idle when the update @@ -264,18 +267,19 @@ def update( pool with that stale configuration until it is discarded (by this flag on a later update, or by flushing the pool). - extensions: List of browser extensions to load into the session. Provide each by id or name. + extensions: If provided, replaces the extension list. Empty array clears all + previously-selected extensions. Omit this field to leave extensions unchanged. - fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10. The cap is 25 for - most organizations but can be raised per-organization, so only the lower bound - is enforced here. + fill_rate_per_minute: If provided, replaces the percentage of the pool to fill per minute. The cap is + 25 for most organizations but can be raised per-organization, so only the lower + bound is enforced here. - headless: If true, launches the browser using a headless image. Defaults to false. + headless: If provided, replaces whether browsers launch using a headless image. - kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live - view. + kiosk_mode: If provided, replaces whether browsers launch in kiosk mode. - name: Optional name for the browser pool. Must be unique within the project. + name: If provided, replaces the pool name. Empty string is a no-op; the pool name + cannot be cleared or reset to empty once assigned. profile: Profile configuration for browsers in a pool. Provide either id or name. Profiles must be created beforehand. Unlike single browser sessions, pools load @@ -283,28 +287,27 @@ def update( omitted here. Any save_changes value sent on a pool profile is silently ignored rather than rejected. - proxy_id: Optional proxy to associate to the browser session. Must reference a proxy in - the same project as the browser session. + proxy_id: Empty string clears the previously-selected proxy. Omit this field to leave the + proxy unchanged. - refresh_on_profile_update: When true, flush idle browsers when the profile the pool uses is updated, so - pool browsers pick up the latest profile data. Requires a profile to be set on - the pool. + refresh_on_profile_update: If provided, replaces whether idle browsers are flushed when the profile the + pool uses is updated. When the pool's profile reference is changed (including + newly attached) and this field is omitted, it defaults to true. Re-sending the + same profile reference leaves this setting unchanged. Clearing the profile also + disables this setting. Requires a profile to be set on the pool. - size: Number of browsers to maintain in the pool. The maximum size is determined by - your organization's pooled sessions limit (the sum of all pool sizes cannot - exceed your limit). + size: If provided, replaces the number of browsers to maintain in the pool. The + maximum size is determined by your organization's pooled sessions limit (the sum + of all pool sizes cannot exceed your limit). - start_url: Optional URL to navigate to when a new browser is warmed into the pool. - Best-effort: failures to navigate do not fail pool fill. Only applied to - newly-warmed browsers; browsers reused via release/acquire keep whatever URL the - previous lease left them on. Accepts any URL Chromium can resolve, including - chrome:// pages. + start_url: If provided, replaces the URL to navigate to when a new browser is warmed into + the pool. Empty string clears the previously-set URL. Omit this field to leave + it unchanged. - stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot - mechanisms. + stealth: If provided, replaces whether browsers launch in stealth mode. - timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they - are destroyed. Defaults to 600 seconds. Minimum 10, maximum 259200 (72 hours). + timeout_seconds: If provided, replaces the default idle timeout in seconds for browsers acquired + from this pool before they are destroyed. Minimum 10, maximum 259200 (72 hours). viewport: Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (1920x1080@25). For GPU images, the default is @@ -361,6 +364,7 @@ def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -376,9 +380,15 @@ def list( Args: limit: Limit the number of browser pools to return. + name: Exact-match filter on browser pool name using the database collation. In + production, matching is case- and accent-insensitive. During the default-project + migration, unscoped requests prefer a concrete default-project browser pool over + a legacy unscoped browser pool with the same name. + offset: Offset the number of browser pools to return. - query: Search browser pools by name or ID. + query: Case-insensitive substring match against browser pool name. IDs match by exact + value. extra_headers: Send extra headers @@ -399,6 +409,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, @@ -663,7 +674,8 @@ async def create( chrome_policy: Custom Chrome enterprise policy overrides applied to all browsers in this pool. Keys are Chrome enterprise policy names; values must match their expected types. Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See - https://chromeenterprise.google/policies/ + https://chromeenterprise.google/policies/ The serialized JSON payload is capped + at 5 MiB. extensions: List of browser extensions to load into the session. Provide each by id or name. @@ -674,7 +686,7 @@ async def create( headless: If true, launches the browser using a headless image. Defaults to false. kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live - view. + view. Defaults to false. name: Optional name for the browser pool. Must be unique within the project. @@ -688,8 +700,8 @@ async def create( the same project as the browser session. refresh_on_profile_update: When true, flush idle browsers when the profile the pool uses is updated, so - pool browsers pick up the latest profile data. Requires a profile to be set on - the pool. + pool browsers pick up the latest profile data. When a profile is provided during + creation, this defaults to true. Requires a profile to be set on the pool. start_url: Optional URL to navigate to when a new browser is warmed into the pool. Best-effort: failures to navigate do not fail pool fill. Only applied to @@ -698,7 +710,7 @@ async def create( chrome:// pages. stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot - mechanisms. + mechanisms. Defaults to false. timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they are destroyed. Defaults to 600 seconds. Minimum 10, maximum 259200 (72 hours). @@ -819,10 +831,12 @@ async def update( `refresh_on_profile_update`. Args: - chrome_policy: Custom Chrome enterprise policy overrides applied to all browsers in this pool. - Keys are Chrome enterprise policy names; values must match their expected types. + chrome_policy: If provided, replaces the custom Chrome enterprise policy overrides applied to + all browsers in this pool. Empty object clears any previously-set policy. Keys + are Chrome enterprise policy names; values must match their expected types. Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See - https://chromeenterprise.google/policies/ + https://chromeenterprise.google/policies/ The serialized JSON payload is capped + at 5 MiB. discard_all_idle: Whether to discard all idle browsers and rebuild them immediately with the new configuration. Defaults to false. Only browsers that are idle when the update @@ -831,18 +845,19 @@ async def update( pool with that stale configuration until it is discarded (by this flag on a later update, or by flushing the pool). - extensions: List of browser extensions to load into the session. Provide each by id or name. + extensions: If provided, replaces the extension list. Empty array clears all + previously-selected extensions. Omit this field to leave extensions unchanged. - fill_rate_per_minute: Percentage of the pool to fill per minute. Defaults to 10. The cap is 25 for - most organizations but can be raised per-organization, so only the lower bound - is enforced here. + fill_rate_per_minute: If provided, replaces the percentage of the pool to fill per minute. The cap is + 25 for most organizations but can be raised per-organization, so only the lower + bound is enforced here. - headless: If true, launches the browser using a headless image. Defaults to false. + headless: If provided, replaces whether browsers launch using a headless image. - kiosk_mode: If true, launches the browser in kiosk mode to hide address bar and tabs in live - view. + kiosk_mode: If provided, replaces whether browsers launch in kiosk mode. - name: Optional name for the browser pool. Must be unique within the project. + name: If provided, replaces the pool name. Empty string is a no-op; the pool name + cannot be cleared or reset to empty once assigned. profile: Profile configuration for browsers in a pool. Provide either id or name. Profiles must be created beforehand. Unlike single browser sessions, pools load @@ -850,28 +865,27 @@ async def update( omitted here. Any save_changes value sent on a pool profile is silently ignored rather than rejected. - proxy_id: Optional proxy to associate to the browser session. Must reference a proxy in - the same project as the browser session. + proxy_id: Empty string clears the previously-selected proxy. Omit this field to leave the + proxy unchanged. - refresh_on_profile_update: When true, flush idle browsers when the profile the pool uses is updated, so - pool browsers pick up the latest profile data. Requires a profile to be set on - the pool. + refresh_on_profile_update: If provided, replaces whether idle browsers are flushed when the profile the + pool uses is updated. When the pool's profile reference is changed (including + newly attached) and this field is omitted, it defaults to true. Re-sending the + same profile reference leaves this setting unchanged. Clearing the profile also + disables this setting. Requires a profile to be set on the pool. - size: Number of browsers to maintain in the pool. The maximum size is determined by - your organization's pooled sessions limit (the sum of all pool sizes cannot - exceed your limit). + size: If provided, replaces the number of browsers to maintain in the pool. The + maximum size is determined by your organization's pooled sessions limit (the sum + of all pool sizes cannot exceed your limit). - start_url: Optional URL to navigate to when a new browser is warmed into the pool. - Best-effort: failures to navigate do not fail pool fill. Only applied to - newly-warmed browsers; browsers reused via release/acquire keep whatever URL the - previous lease left them on. Accepts any URL Chromium can resolve, including - chrome:// pages. + start_url: If provided, replaces the URL to navigate to when a new browser is warmed into + the pool. Empty string clears the previously-set URL. Omit this field to leave + it unchanged. - stealth: If true, launches the browser in stealth mode to reduce detection by anti-bot - mechanisms. + stealth: If provided, replaces whether browsers launch in stealth mode. - timeout_seconds: Default idle timeout in seconds for browsers acquired from this pool before they - are destroyed. Defaults to 600 seconds. Minimum 10, maximum 259200 (72 hours). + timeout_seconds: If provided, replaces the default idle timeout in seconds for browsers acquired + from this pool before they are destroyed. Minimum 10, maximum 259200 (72 hours). viewport: Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (1920x1080@25). For GPU images, the default is @@ -928,6 +942,7 @@ def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -943,9 +958,15 @@ def list( Args: limit: Limit the number of browser pools to return. + name: Exact-match filter on browser pool name using the database collation. In + production, matching is case- and accent-insensitive. During the default-project + migration, unscoped requests prefer a concrete default-project browser pool over + a legacy unscoped browser pool with the same name. + offset: Offset the number of browser pools to return. - query: Search browser pools by name or ID. + query: Case-insensitive substring match against browser pool name. IDs match by exact + value. extra_headers: Send extra headers @@ -966,6 +987,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, diff --git a/src/kernel/resources/credential_providers.py b/src/kernel/resources/credential_providers.py index 00db5c5e..de079a8c 100644 --- a/src/kernel/resources/credential_providers.py +++ b/src/kernel/resources/credential_providers.py @@ -216,7 +216,8 @@ def list( offset: Offset the number of credential providers to return. - query: Search credential providers by name or ID. + query: Case-insensitive substring match against credential provider name. IDs match by + exact value. extra_headers: Send extra headers @@ -534,7 +535,8 @@ def list( offset: Offset the number of credential providers to return. - query: Search credential providers by name or ID. + query: Case-insensitive substring match against credential provider name. IDs match by + exact value. extra_headers: Send extra headers diff --git a/src/kernel/resources/credentials.py b/src/kernel/resources/credentials.py index fd073957..f1a3ac01 100644 --- a/src/kernel/resources/credentials.py +++ b/src/kernel/resources/credentials.py @@ -229,7 +229,8 @@ def list( offset: Number of results to skip - query: Search credentials by name, domain, or ID. + query: Case-insensitive substring match against credential name or domain. IDs match by + exact value. extra_headers: Send extra headers @@ -534,7 +535,8 @@ def list( offset: Number of results to skip - query: Search credentials by name, domain, or ID. + query: Case-insensitive substring match against credential name or domain. IDs match by + exact value. extra_headers: Send extra headers diff --git a/src/kernel/resources/extensions.py b/src/kernel/resources/extensions.py index 5c023531..81a1ff9a 100644 --- a/src/kernel/resources/extensions.py +++ b/src/kernel/resources/extensions.py @@ -62,6 +62,7 @@ def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -77,9 +78,15 @@ def list( Args: limit: Limit the number of extensions to return. + name: Exact-match filter on extension name using the database collation. In + production, matching is case- and accent-insensitive. During the default-project + migration, unscoped requests prefer a concrete default-project extension over a + legacy unscoped extension with the same name. + offset: Offset the number of extensions to return. - query: Search extensions by name or ID. + query: Case-insensitive substring match against extension name. IDs match by exact + value. extra_headers: Send extra headers @@ -100,6 +107,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, @@ -338,6 +346,7 @@ def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -353,9 +362,15 @@ def list( Args: limit: Limit the number of extensions to return. + name: Exact-match filter on extension name using the database collation. In + production, matching is case- and accent-insensitive. During the default-project + migration, unscoped requests prefer a concrete default-project extension over a + legacy unscoped extension with the same name. + offset: Offset the number of extensions to return. - query: Search extensions by name or ID. + query: Case-insensitive substring match against extension name. IDs match by exact + value. extra_headers: Send extra headers @@ -376,6 +391,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, diff --git a/src/kernel/resources/organization/limits.py b/src/kernel/resources/organization/limits.py index 4bf68845..d30bfbfa 100644 --- a/src/kernel/resources/organization/limits.py +++ b/src/kernel/resources/organization/limits.py @@ -56,8 +56,9 @@ def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> OrgLimits: """ - Get the organization's concurrent session ceiling and the default per-project - concurrency cap applied to projects without an explicit override. + Get the organization's concurrency limit — the maximum browsers running at once + across on-demand sessions and browser pool reservations — and the default + per-project concurrency cap applied to projects without an explicit override. """ return self._get( "/org/limits", @@ -81,13 +82,12 @@ def update( """ Set the default per-project concurrency cap applied to projects without an explicit override. Set the value to 0 to remove the default; omit to leave it - unchanged. The default cannot exceed the organization's concurrent session - ceiling. + unchanged. The default cannot exceed the organization's concurrency limit. Args: - default_project_max_concurrent_sessions: Default maximum concurrent browser sessions for projects without an explicit - override. Set to 0 to remove the default; omit to leave unchanged. Cannot exceed - the organization's concurrent session ceiling. + default_project_max_concurrent_sessions: Default maximum concurrent browsers for projects without an explicit override. + Set to 0 to remove the default; omit to leave unchanged. Cannot exceed the + organization's concurrency limit. extra_headers: Send extra headers @@ -143,8 +143,9 @@ async def retrieve( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> OrgLimits: """ - Get the organization's concurrent session ceiling and the default per-project - concurrency cap applied to projects without an explicit override. + Get the organization's concurrency limit — the maximum browsers running at once + across on-demand sessions and browser pool reservations — and the default + per-project concurrency cap applied to projects without an explicit override. """ return await self._get( "/org/limits", @@ -168,13 +169,12 @@ async def update( """ Set the default per-project concurrency cap applied to projects without an explicit override. Set the value to 0 to remove the default; omit to leave it - unchanged. The default cannot exceed the organization's concurrent session - ceiling. + unchanged. The default cannot exceed the organization's concurrency limit. Args: - default_project_max_concurrent_sessions: Default maximum concurrent browser sessions for projects without an explicit - override. Set to 0 to remove the default; omit to leave unchanged. Cannot exceed - the organization's concurrent session ceiling. + default_project_max_concurrent_sessions: Default maximum concurrent browsers for projects without an explicit override. + Set to 0 to remove the default; omit to leave unchanged. Cannot exceed the + organization's concurrency limit. extra_headers: Send extra headers diff --git a/src/kernel/resources/profiles.py b/src/kernel/resources/profiles.py index 4083f12d..e804f559 100644 --- a/src/kernel/resources/profiles.py +++ b/src/kernel/resources/profiles.py @@ -4,7 +4,7 @@ import httpx -from ..types import profile_list_params, profile_create_params +from ..types import profile_list_params, profile_create_params, profile_update_params from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property @@ -68,7 +68,9 @@ def create( sessions. Args: - name: Optional name of the profile. Must be unique within the project. + name: Optional name of the profile. Must be unique within the logical project; during + the default-project migration, unscoped profiles and profiles in the org default + project are treated as the same project. extra_headers: Send extra headers @@ -120,10 +122,57 @@ def retrieve( cast_to=Profile, ) + def update( + self, + id_or_name: str, + *, + name: str, + # 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, + ) -> Profile: + """Update a profile's name. + + Names must be unique within the logical project; during + the default-project migration, unscoped profiles and profiles in the org default + project are treated as the same project. Duplicate-name conflicts are checked + before update but are best-effort because there is no backing unique index. + Renaming a profile while a browser session references it by name may prevent + that session's changes from saving; prefer renaming when the profile is not in + use. + + Args: + name: New profile name. Must be unique within the logical project; during the + default-project migration, unscoped profiles and profiles in the org default + project are treated as the same project. + + 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 id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._patch( + path_template("/profiles/{id_or_name}", id_or_name=id_or_name), + body=maybe_transform({"name": name}, profile_update_params.ProfileUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Profile, + ) + def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -139,9 +188,14 @@ def list( Args: limit: Limit the number of profiles to return. + name: Exact-match filter on profile name using the database collation. In production, + matching is case- and accent-insensitive. During the default-project migration, + unscoped requests prefer a concrete default-project profile over a legacy + unscoped profile with the same name. + offset: Offset the number of profiles to return. - query: Search profiles by name or ID. + query: Case-insensitive substring match against profile name or ID. extra_headers: Send extra headers @@ -162,6 +216,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, @@ -278,7 +333,9 @@ async def create( sessions. Args: - name: Optional name of the profile. Must be unique within the project. + name: Optional name of the profile. Must be unique within the logical project; during + the default-project migration, unscoped profiles and profiles in the org default + project are treated as the same project. extra_headers: Send extra headers @@ -330,10 +387,57 @@ async def retrieve( cast_to=Profile, ) + async def update( + self, + id_or_name: str, + *, + name: str, + # 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, + ) -> Profile: + """Update a profile's name. + + Names must be unique within the logical project; during + the default-project migration, unscoped profiles and profiles in the org default + project are treated as the same project. Duplicate-name conflicts are checked + before update but are best-effort because there is no backing unique index. + Renaming a profile while a browser session references it by name may prevent + that session's changes from saving; prefer renaming when the profile is not in + use. + + Args: + name: New profile name. Must be unique within the logical project; during the + default-project migration, unscoped profiles and profiles in the org default + project are treated as the same project. + + 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 id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._patch( + path_template("/profiles/{id_or_name}", id_or_name=id_or_name), + body=await async_maybe_transform({"name": name}, profile_update_params.ProfileUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Profile, + ) + def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -349,9 +453,14 @@ def list( Args: limit: Limit the number of profiles to return. + name: Exact-match filter on profile name using the database collation. In production, + matching is case- and accent-insensitive. During the default-project migration, + unscoped requests prefer a concrete default-project profile over a legacy + unscoped profile with the same name. + offset: Offset the number of profiles to return. - query: Search profiles by name or ID. + query: Case-insensitive substring match against profile name or ID. extra_headers: Send extra headers @@ -372,6 +481,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, @@ -460,6 +570,9 @@ def __init__(self, profiles: ProfilesResource) -> None: self.retrieve = to_raw_response_wrapper( profiles.retrieve, ) + self.update = to_raw_response_wrapper( + profiles.update, + ) self.list = to_raw_response_wrapper( profiles.list, ) @@ -482,6 +595,9 @@ def __init__(self, profiles: AsyncProfilesResource) -> None: self.retrieve = async_to_raw_response_wrapper( profiles.retrieve, ) + self.update = async_to_raw_response_wrapper( + profiles.update, + ) self.list = async_to_raw_response_wrapper( profiles.list, ) @@ -504,6 +620,9 @@ def __init__(self, profiles: ProfilesResource) -> None: self.retrieve = to_streamed_response_wrapper( profiles.retrieve, ) + self.update = to_streamed_response_wrapper( + profiles.update, + ) self.list = to_streamed_response_wrapper( profiles.list, ) @@ -526,6 +645,9 @@ def __init__(self, profiles: AsyncProfilesResource) -> None: self.retrieve = async_to_streamed_response_wrapper( profiles.retrieve, ) + self.update = async_to_streamed_response_wrapper( + profiles.update, + ) self.list = async_to_streamed_response_wrapper( profiles.list, ) diff --git a/src/kernel/resources/projects/limits.py b/src/kernel/resources/projects/limits.py index ade9302c..1e05711f 100644 --- a/src/kernel/resources/projects/limits.py +++ b/src/kernel/resources/projects/limits.py @@ -104,11 +104,13 @@ def update( max_concurrent_invocations: Maximum concurrent app invocations for this project. Set to 0 to remove the cap; omit to leave unchanged. - max_concurrent_sessions: Maximum concurrent browser sessions for this project. Set to 0 to remove the - cap; omit to leave unchanged. + max_concurrent_sessions: Maximum concurrent browsers for this project, covering both on-demand sessions + and browser pool reservations. Set to 0 to remove the cap; omit to leave + unchanged. - max_pooled_sessions: Maximum pooled sessions capacity for this project. Set to 0 to remove the cap; - omit to leave unchanged. + max_pooled_sessions: Deprecated: pooled browsers now count toward `max_concurrent_sessions`. Requests + that set this field are rejected with a 400 once the unified concurrency limit + is enabled for your organization. extra_headers: Send extra headers @@ -218,11 +220,13 @@ async def update( max_concurrent_invocations: Maximum concurrent app invocations for this project. Set to 0 to remove the cap; omit to leave unchanged. - max_concurrent_sessions: Maximum concurrent browser sessions for this project. Set to 0 to remove the - cap; omit to leave unchanged. + max_concurrent_sessions: Maximum concurrent browsers for this project, covering both on-demand sessions + and browser pool reservations. Set to 0 to remove the cap; omit to leave + unchanged. - max_pooled_sessions: Maximum pooled sessions capacity for this project. Set to 0 to remove the cap; - omit to leave unchanged. + max_pooled_sessions: Deprecated: pooled browsers now count toward `max_concurrent_sessions`. Requests + that set this field are rejected with a 400 once the unified concurrency limit + is enabled for your organization. extra_headers: Send extra headers diff --git a/src/kernel/resources/projects/projects.py b/src/kernel/resources/projects/projects.py index 786a6c1f..c8ca08f2 100644 --- a/src/kernel/resources/projects/projects.py +++ b/src/kernel/resources/projects/projects.py @@ -177,6 +177,7 @@ def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -192,6 +193,9 @@ def list( Args: limit: Maximum number of results to return + name: Exact-match filter on project name using the database collation. In production, + matching is case- and accent-insensitive. + offset: Number of results to skip query: Case-insensitive substring match against project name @@ -215,6 +219,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, @@ -405,6 +410,7 @@ def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -420,6 +426,9 @@ def list( Args: limit: Maximum number of results to return + name: Exact-match filter on project name using the database collation. In production, + matching is case- and accent-insensitive. + offset: Number of results to skip query: Case-insensitive substring match against project name @@ -443,6 +452,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, diff --git a/src/kernel/resources/proxies.py b/src/kernel/resources/proxies.py index 0b4902de..08f97e37 100644 --- a/src/kernel/resources/proxies.py +++ b/src/kernel/resources/proxies.py @@ -6,7 +6,7 @@ import httpx -from ..types import proxy_list_params, proxy_check_params, proxy_create_params +from ..types import proxy_list_params, proxy_check_params, proxy_create_params, proxy_update_params from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given from .._utils import path_template, maybe_transform, async_maybe_transform from .._compat import cached_property @@ -22,6 +22,7 @@ from ..types.proxy_list_response import ProxyListResponse from ..types.proxy_check_response import ProxyCheckResponse from ..types.proxy_create_response import ProxyCreateResponse +from ..types.proxy_update_response import ProxyUpdateResponse from ..types.proxy_retrieve_response import ProxyRetrieveResponse __all__ = ["ProxiesResource", "AsyncProxiesResource"] @@ -138,10 +139,53 @@ def retrieve( cast_to=ProxyRetrieveResponse, ) + def update( + self, + id: str, + *, + name: str, + # 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, + ) -> ProxyUpdateResponse: + """Update a proxy's name. + + Proxy names are not unique and are not ID-or-name + addressable on this endpoint; duplicate names are allowed. Name-based + session-create lookups can remain ambiguous until callers resolve proxies by ID + or the API adds a stronger uniqueness contract. + + Args: + name: New proxy name. Proxy names are trimmed and length-checked only; duplicates are + allowed because proxies are updated by ID, not by name. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._patch( + path_template("/proxies/{id}", id=id), + body=maybe_transform({"name": name}, proxy_update_params.ProxyUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProxyUpdateResponse, + ) + def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -157,9 +201,14 @@ def list( Args: limit: Limit the number of proxies to return. + name: Exact-match filter on proxy name using the database collation. In production, + matching is case- and accent-insensitive. Names are not required to be unique, + so multiple proxies may match. + offset: Offset the number of proxies to return. - query: Search proxies by name, host, IP address, or ID. + query: Case-insensitive substring match against proxy name, host, or IP address. IDs + match by exact value. extra_headers: Send extra headers @@ -180,6 +229,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, @@ -390,10 +440,53 @@ async def retrieve( cast_to=ProxyRetrieveResponse, ) + async def update( + self, + id: str, + *, + name: str, + # 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, + ) -> ProxyUpdateResponse: + """Update a proxy's name. + + Proxy names are not unique and are not ID-or-name + addressable on this endpoint; duplicate names are allowed. Name-based + session-create lookups can remain ambiguous until callers resolve proxies by ID + or the API adds a stronger uniqueness contract. + + Args: + name: New proxy name. Proxy names are trimmed and length-checked only; duplicates are + allowed because proxies are updated by ID, not by name. + + 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 id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._patch( + path_template("/proxies/{id}", id=id), + body=await async_maybe_transform({"name": name}, proxy_update_params.ProxyUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProxyUpdateResponse, + ) + def list( self, *, limit: int | Omit = omit, + name: str | Omit = omit, offset: int | Omit = omit, query: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -409,9 +502,14 @@ def list( Args: limit: Limit the number of proxies to return. + name: Exact-match filter on proxy name using the database collation. In production, + matching is case- and accent-insensitive. Names are not required to be unique, + so multiple proxies may match. + offset: Offset the number of proxies to return. - query: Search proxies by name, host, IP address, or ID. + query: Case-insensitive substring match against proxy name, host, or IP address. IDs + match by exact value. extra_headers: Send extra headers @@ -432,6 +530,7 @@ def list( query=maybe_transform( { "limit": limit, + "name": name, "offset": offset, "query": query, }, @@ -541,6 +640,9 @@ def __init__(self, proxies: ProxiesResource) -> None: self.retrieve = to_raw_response_wrapper( proxies.retrieve, ) + self.update = to_raw_response_wrapper( + proxies.update, + ) self.list = to_raw_response_wrapper( proxies.list, ) @@ -562,6 +664,9 @@ def __init__(self, proxies: AsyncProxiesResource) -> None: self.retrieve = async_to_raw_response_wrapper( proxies.retrieve, ) + self.update = async_to_raw_response_wrapper( + proxies.update, + ) self.list = async_to_raw_response_wrapper( proxies.list, ) @@ -583,6 +688,9 @@ def __init__(self, proxies: ProxiesResource) -> None: self.retrieve = to_streamed_response_wrapper( proxies.retrieve, ) + self.update = to_streamed_response_wrapper( + proxies.update, + ) self.list = to_streamed_response_wrapper( proxies.list, ) @@ -604,6 +712,9 @@ def __init__(self, proxies: AsyncProxiesResource) -> None: self.retrieve = async_to_streamed_response_wrapper( proxies.retrieve, ) + self.update = async_to_streamed_response_wrapper( + proxies.update, + ) self.list = async_to_streamed_response_wrapper( proxies.list, ) diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index 49af1d5c..959865bf 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -38,6 +38,7 @@ from .project_list_params import ProjectListParams as ProjectListParams from .proxy_create_params import ProxyCreateParams as ProxyCreateParams from .proxy_list_response import ProxyListResponse as ProxyListResponse +from .proxy_update_params import ProxyUpdateParams as ProxyUpdateParams from .proxy_check_response import ProxyCheckResponse as ProxyCheckResponse from .api_key_create_params import APIKeyCreateParams as APIKeyCreateParams from .api_key_rotate_params import APIKeyRotateParams as APIKeyRotateParams @@ -49,9 +50,11 @@ from .browser_update_params import BrowserUpdateParams as BrowserUpdateParams from .extension_list_params import ExtensionListParams as ExtensionListParams from .profile_create_params import ProfileCreateParams as ProfileCreateParams +from .profile_update_params import ProfileUpdateParams as ProfileUpdateParams from .project_create_params import ProjectCreateParams as ProjectCreateParams from .project_update_params import ProjectUpdateParams as ProjectUpdateParams from .proxy_create_response import ProxyCreateResponse as ProxyCreateResponse +from .proxy_update_response import ProxyUpdateResponse as ProxyUpdateResponse from .credential_list_params import CredentialListParams as CredentialListParams from .deployment_list_params import DeploymentListParams as DeploymentListParams from .deployment_state_event import DeploymentStateEvent as DeploymentStateEvent diff --git a/src/kernel/types/api_key.py b/src/kernel/types/api_key.py index 44519527..b0d6eef2 100644 --- a/src/kernel/types/api_key.py +++ b/src/kernel/types/api_key.py @@ -41,7 +41,11 @@ class APIKey(BaseModel): """Masked version of the API key""" name: str - """API key name""" + """Label for the API key. + + API keys are not addressable by name; use the ID or key identifier for stable + references. + """ project_id: Optional[str] = None """Project identifier for project-scoped API keys. Null means org-wide.""" diff --git a/src/kernel/types/api_key_create_params.py b/src/kernel/types/api_key_create_params.py index 7705108f..2909510e 100644 --- a/src/kernel/types/api_key_create_params.py +++ b/src/kernel/types/api_key_create_params.py @@ -10,7 +10,7 @@ class APIKeyCreateParams(TypedDict, total=False): name: Required[str] - """API key name (1-255 characters)""" + """Label for the API key (1-255 characters). API keys are not addressable by name.""" days_to_expire: Optional[int] """Number of days until expiry, up to 3650. Use null for never.""" diff --git a/src/kernel/types/api_key_list_params.py b/src/kernel/types/api_key_list_params.py index 3ddc2a38..95b8af5f 100644 --- a/src/kernel/types/api_key_list_params.py +++ b/src/kernel/types/api_key_list_params.py @@ -18,6 +18,15 @@ class APIKeyListParams(TypedDict, total=False): limit: int """Maximum number of results to return""" + name: str + """Exact-match filter on API key name using the database collation. + + In production, matching is case- and accent-insensitive. Names are not required + to be unique, so multiple keys may match. When status=all or + include_deleted=true is set, soft-deleted keys with the same name may also + match. + """ + offset: int """Number of results to skip""" diff --git a/src/kernel/types/audit_log_export_chunk_params.py b/src/kernel/types/audit_log_export_chunk_params.py index 8e759c9f..5cc07b03 100644 --- a/src/kernel/types/audit_log_export_chunk_params.py +++ b/src/kernel/types/audit_log_export_chunk_params.py @@ -25,7 +25,7 @@ class AuditLogExportChunkParams(TypedDict, total=False): cursor: str """Opaque cursor from X-Next-Cursor for the next chunk of older records.""" - exclude_method: str + exclude_method: SequenceNotStr[str] """Filter out results by HTTP method.""" format: Literal["jsonl", "jsonl.gz"] diff --git a/src/kernel/types/audit_log_list_params.py b/src/kernel/types/audit_log_list_params.py index f1e18f58..b3329e70 100644 --- a/src/kernel/types/audit_log_list_params.py +++ b/src/kernel/types/audit_log_list_params.py @@ -22,7 +22,7 @@ class AuditLogListParams(TypedDict, total=False): auth_strategy: str """Filter by authentication strategy.""" - exclude_method: str + exclude_method: SequenceNotStr[str] """Filter out results by HTTP method.""" limit: int diff --git a/src/kernel/types/auth/connection_create_params.py b/src/kernel/types/auth/connection_create_params.py index e5a969ce..0113d062 100644 --- a/src/kernel/types/auth/connection_create_params.py +++ b/src/kernel/types/auth/connection_create_params.py @@ -84,7 +84,9 @@ class ConnectionCreateParams(TypedDict, total=False): """Proxy selection. Provide either id or name. The proxy must be in the same project as the resource - referencing it. + referencing it. When selecting by name, the name must match exactly one active + proxy in the project. Ambiguous names return a 400; use id for stable + references. """ record_session: bool @@ -126,6 +128,7 @@ class Proxy(TypedDict, total=False): """Proxy selection. Provide either id or name. The proxy must be in the same project as the resource referencing it. + When selecting by name, the name must match exactly one active proxy in the project. Ambiguous names return a 400; use id for stable references. """ id: str diff --git a/src/kernel/types/auth/connection_login_params.py b/src/kernel/types/auth/connection_login_params.py index 5e136cc3..6cfa737a 100644 --- a/src/kernel/types/auth/connection_login_params.py +++ b/src/kernel/types/auth/connection_login_params.py @@ -12,7 +12,9 @@ class ConnectionLoginParams(TypedDict, total=False): """Proxy selection. Provide either id or name. The proxy must be in the same project as the resource - referencing it. + referencing it. When selecting by name, the name must match exactly one active + proxy in the project. Ambiguous names return a 400; use id for stable + references. """ record_session: bool @@ -26,6 +28,7 @@ class Proxy(TypedDict, total=False): """Proxy selection. Provide either id or name. The proxy must be in the same project as the resource referencing it. + When selecting by name, the name must match exactly one active proxy in the project. Ambiguous names return a 400; use id for stable references. """ id: str diff --git a/src/kernel/types/auth/connection_update_params.py b/src/kernel/types/auth/connection_update_params.py index e0dadf70..20bc98ab 100644 --- a/src/kernel/types/auth/connection_update_params.py +++ b/src/kernel/types/auth/connection_update_params.py @@ -51,7 +51,9 @@ class ConnectionUpdateParams(TypedDict, total=False): """Proxy selection. Provide either id or name. The proxy must be in the same project as the resource - referencing it. + referencing it. When selecting by name, the name must match exactly one active + proxy in the project. Ambiguous names return a 400; use id for stable + references. """ record_session: bool @@ -87,6 +89,7 @@ class Proxy(TypedDict, total=False): """Proxy selection. Provide either id or name. The proxy must be in the same project as the resource referencing it. + When selecting by name, the name must match exactly one active proxy in the project. Ambiguous names return a 400; use id for stable references. """ id: str diff --git a/src/kernel/types/browser_pool.py b/src/kernel/types/browser_pool.py index 78860923..4f7764ab 100644 --- a/src/kernel/types/browser_pool.py +++ b/src/kernel/types/browser_pool.py @@ -33,7 +33,7 @@ class BrowserPoolConfig(BaseModel): """Configuration used to create all browsers in this pool""" size: int - """Number of browsers to maintain in the pool. + """Number of browsers maintained in the pool. The maximum size is determined by your organization's pooled sessions limit (the sum of all pool sizes cannot exceed your limit). @@ -44,7 +44,8 @@ class BrowserPoolConfig(BaseModel): Keys are Chrome enterprise policy names; values must match their expected types. Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See - https://chromeenterprise.google/policies/ + https://chromeenterprise.google/policies/ The serialized JSON payload is capped + at 5 MiB. """ extensions: Optional[List[BrowserExtension]] = None @@ -56,12 +57,12 @@ class BrowserPoolConfig(BaseModel): fill_rate_per_minute: Optional[int] = None """Percentage of the pool to fill per minute. - Defaults to 10. The cap is 25 for most organizations but can be raised - per-organization, so only the lower bound is enforced here. + The cap is 25 for most organizations but can be raised per-organization, so only + the lower bound is enforced here. """ headless: Optional[bool] = None - """If true, launches the browser using a headless image. Defaults to false.""" + """If true, launches the browser using a headless image.""" kiosk_mode: Optional[bool] = None """ @@ -82,16 +83,16 @@ class BrowserPoolConfig(BaseModel): """ proxy_id: Optional[str] = None - """Optional proxy to associate to the browser session. + """Optional proxy associated to the browser session. - Must reference a proxy in the same project as the browser session. + References a proxy in the same project as the browser session. """ refresh_on_profile_update: Optional[bool] = None """ When true, flush idle browsers when the profile the pool uses is updated, so - pool browsers pick up the latest profile data. Requires a profile to be set on - the pool. + pool browsers pick up the latest profile data. When a profile is provided during + creation, this defaults to true. Requires a profile to be set on the pool. """ start_url: Optional[str] = None @@ -112,7 +113,7 @@ class BrowserPoolConfig(BaseModel): timeout_seconds: Optional[int] = None """ Default idle timeout in seconds for browsers acquired from this pool before they - are destroyed. Defaults to 600 seconds. Minimum 10, maximum 259200 (72 hours). + are destroyed. Minimum 10, maximum 259200 (72 hours). """ viewport: Optional[BrowserViewport] = None diff --git a/src/kernel/types/browser_pool_create_params.py b/src/kernel/types/browser_pool_create_params.py index 5d4d9760..328ac743 100644 --- a/src/kernel/types/browser_pool_create_params.py +++ b/src/kernel/types/browser_pool_create_params.py @@ -24,7 +24,8 @@ class BrowserPoolCreateParams(TypedDict, total=False): Keys are Chrome enterprise policy names; values must match their expected types. Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See - https://chromeenterprise.google/policies/ + https://chromeenterprise.google/policies/ The serialized JSON payload is capped + at 5 MiB. """ extensions: Iterable[BrowserExtension] @@ -46,7 +47,7 @@ class BrowserPoolCreateParams(TypedDict, total=False): kiosk_mode: bool """ If true, launches the browser in kiosk mode to hide address bar and tabs in live - view. + view. Defaults to false. """ name: str @@ -70,8 +71,8 @@ class BrowserPoolCreateParams(TypedDict, total=False): refresh_on_profile_update: bool """ When true, flush idle browsers when the profile the pool uses is updated, so - pool browsers pick up the latest profile data. Requires a profile to be set on - the pool. + pool browsers pick up the latest profile data. When a profile is provided during + creation, this defaults to true. Requires a profile to be set on the pool. """ start_url: str @@ -86,7 +87,7 @@ class BrowserPoolCreateParams(TypedDict, total=False): stealth: bool """ If true, launches the browser in stealth mode to reduce detection by anti-bot - mechanisms. + mechanisms. Defaults to false. """ timeout_seconds: int diff --git a/src/kernel/types/browser_pool_list_params.py b/src/kernel/types/browser_pool_list_params.py index 26436a61..75fea5db 100644 --- a/src/kernel/types/browser_pool_list_params.py +++ b/src/kernel/types/browser_pool_list_params.py @@ -11,8 +11,19 @@ class BrowserPoolListParams(TypedDict, total=False): limit: int """Limit the number of browser pools to return.""" + name: str + """Exact-match filter on browser pool name using the database collation. + + In production, matching is case- and accent-insensitive. During the + default-project migration, unscoped requests prefer a concrete default-project + browser pool over a legacy unscoped browser pool with the same name. + """ + offset: int """Offset the number of browser pools to return.""" query: str - """Search browser pools by name or ID.""" + """Case-insensitive substring match against browser pool name. + + IDs match by exact value. + """ diff --git a/src/kernel/types/browser_pool_update_params.py b/src/kernel/types/browser_pool_update_params.py index d504e29d..a4c65578 100644 --- a/src/kernel/types/browser_pool_update_params.py +++ b/src/kernel/types/browser_pool_update_params.py @@ -13,11 +13,13 @@ class BrowserPoolUpdateParams(TypedDict, total=False): chrome_policy: Dict[str, object] - """Custom Chrome enterprise policy overrides applied to all browsers in this pool. - - Keys are Chrome enterprise policy names; values must match their expected types. + """ + If provided, replaces the custom Chrome enterprise policy overrides applied to + all browsers in this pool. Empty object clears any previously-set policy. Keys + are Chrome enterprise policy names; values must match their expected types. Blocked: kernel-managed policies (extensions, proxy, CDP/automation). See - https://chromeenterprise.google/policies/ + https://chromeenterprise.google/policies/ The serialized JSON payload is capped + at 5 MiB. """ discard_all_idle: bool @@ -31,29 +33,31 @@ class BrowserPoolUpdateParams(TypedDict, total=False): """ extensions: Iterable[BrowserExtension] - """List of browser extensions to load into the session. + """If provided, replaces the extension list. - Provide each by id or name. + Empty array clears all previously-selected extensions. Omit this field to leave + extensions unchanged. """ fill_rate_per_minute: int - """Percentage of the pool to fill per minute. + """If provided, replaces the percentage of the pool to fill per minute. - Defaults to 10. The cap is 25 for most organizations but can be raised - per-organization, so only the lower bound is enforced here. + The cap is 25 for most organizations but can be raised per-organization, so only + the lower bound is enforced here. """ headless: bool - """If true, launches the browser using a headless image. Defaults to false.""" + """If provided, replaces whether browsers launch using a headless image.""" kiosk_mode: bool - """ - If true, launches the browser in kiosk mode to hide address bar and tabs in live - view. - """ + """If provided, replaces whether browsers launch in kiosk mode.""" name: str - """Optional name for the browser pool. Must be unique within the project.""" + """If provided, replaces the pool name. + + Empty string is a no-op; the pool name cannot be cleared or reset to empty once + assigned. + """ profile: Profile """Profile configuration for browsers in a pool. @@ -65,44 +69,41 @@ class BrowserPoolUpdateParams(TypedDict, total=False): """ proxy_id: str - """Optional proxy to associate to the browser session. + """Empty string clears the previously-selected proxy. - Must reference a proxy in the same project as the browser session. + Omit this field to leave the proxy unchanged. """ refresh_on_profile_update: bool """ - When true, flush idle browsers when the profile the pool uses is updated, so - pool browsers pick up the latest profile data. Requires a profile to be set on - the pool. + If provided, replaces whether idle browsers are flushed when the profile the + pool uses is updated. When the pool's profile reference is changed (including + newly attached) and this field is omitted, it defaults to true. Re-sending the + same profile reference leaves this setting unchanged. Clearing the profile also + disables this setting. Requires a profile to be set on the pool. """ size: int - """Number of browsers to maintain in the pool. + """If provided, replaces the number of browsers to maintain in the pool. The maximum size is determined by your organization's pooled sessions limit (the sum of all pool sizes cannot exceed your limit). """ start_url: str - """Optional URL to navigate to when a new browser is warmed into the pool. - - Best-effort: failures to navigate do not fail pool fill. Only applied to - newly-warmed browsers; browsers reused via release/acquire keep whatever URL the - previous lease left them on. Accepts any URL Chromium can resolve, including - chrome:// pages. + """ + If provided, replaces the URL to navigate to when a new browser is warmed into + the pool. Empty string clears the previously-set URL. Omit this field to leave + it unchanged. """ stealth: bool - """ - If true, launches the browser in stealth mode to reduce detection by anti-bot - mechanisms. - """ + """If provided, replaces whether browsers launch in stealth mode.""" timeout_seconds: int """ - Default idle timeout in seconds for browsers acquired from this pool before they - are destroyed. Defaults to 600 seconds. Minimum 10, maximum 259200 (72 hours). + If provided, replaces the default idle timeout in seconds for browsers acquired + from this pool before they are destroyed. Minimum 10, maximum 259200 (72 hours). """ viewport: BrowserViewport diff --git a/src/kernel/types/browsers/browser_console_error_event.py b/src/kernel/types/browsers/browser_console_error_event.py index 72a93ede..ef1c8949 100644 --- a/src/kernel/types/browsers/browser_console_error_event.py +++ b/src/kernel/types/browsers/browser_console_error_event.py @@ -19,7 +19,12 @@ class Data(BrowserEventContext): """ text: str - """Error message text. Present in both source paths.""" + """Human-readable error text, as the browser console would display it. + + For console.error() calls, the first argument coerced to a string. For uncaught + exceptions, the prefix and error message, e.g. "Uncaught Error: boom" or + "Uncaught (in promise) TypeError: x is not a function". + """ args: Optional[List[str]] = None """All console arguments coerced to strings. diff --git a/src/kernel/types/credential_list_params.py b/src/kernel/types/credential_list_params.py index 50e25895..ecaf2ef1 100644 --- a/src/kernel/types/credential_list_params.py +++ b/src/kernel/types/credential_list_params.py @@ -18,4 +18,7 @@ class CredentialListParams(TypedDict, total=False): """Number of results to skip""" query: str - """Search credentials by name, domain, or ID.""" + """Case-insensitive substring match against credential name or domain. + + IDs match by exact value. + """ diff --git a/src/kernel/types/credential_provider_list_params.py b/src/kernel/types/credential_provider_list_params.py index 69005988..97571aa8 100644 --- a/src/kernel/types/credential_provider_list_params.py +++ b/src/kernel/types/credential_provider_list_params.py @@ -15,4 +15,7 @@ class CredentialProviderListParams(TypedDict, total=False): """Offset the number of credential providers to return.""" query: str - """Search credential providers by name or ID.""" + """Case-insensitive substring match against credential provider name. + + IDs match by exact value. + """ diff --git a/src/kernel/types/deployment_create_response.py b/src/kernel/types/deployment_create_response.py index 17d17b59..439ed52a 100644 --- a/src/kernel/types/deployment_create_response.py +++ b/src/kernel/types/deployment_create_response.py @@ -35,6 +35,39 @@ class DeploymentCreateResponse(BaseModel): values. """ + source_checksum: Optional[str] = None + """Hex-encoded SHA-256 checksum of the source archive. + + For file uploads, this hashes the uploaded archive; for GitHub-sourced + deployments, this hashes the GitHub archive downloaded by the API. Omitted for + deployments created before this field was recorded. + """ + + source_path: Optional[str] = None + """ + For GitHub-sourced deployments, the subpath within the repository that was used + as the deploy root. Omitted when the repo root was used or for file uploads. + """ + + source_ref: Optional[str] = None + """ + For GitHub-sourced deployments, the git ref as requested at deploy time (branch, + tag, or commit SHA — not resolved to a commit). Omitted for file uploads. + """ + + source_type: Optional[Literal["file", "github"]] = None + """Origin of the deployed source code. + + This is read-only response provenance; `file` indicates an uploaded archive and + `github` indicates a repository fetched by the API. + """ + + source_url: Optional[str] = None + """For GitHub-sourced deployments, the repository URL that was fetched. + + Omitted for file uploads. + """ + status_reason: Optional[str] = None """Status reason""" diff --git a/src/kernel/types/deployment_list_response.py b/src/kernel/types/deployment_list_response.py index 5806bdaf..accd0d05 100644 --- a/src/kernel/types/deployment_list_response.py +++ b/src/kernel/types/deployment_list_response.py @@ -35,6 +35,39 @@ class DeploymentListResponse(BaseModel): values. """ + source_checksum: Optional[str] = None + """Hex-encoded SHA-256 checksum of the source archive. + + For file uploads, this hashes the uploaded archive; for GitHub-sourced + deployments, this hashes the GitHub archive downloaded by the API. Omitted for + deployments created before this field was recorded. + """ + + source_path: Optional[str] = None + """ + For GitHub-sourced deployments, the subpath within the repository that was used + as the deploy root. Omitted when the repo root was used or for file uploads. + """ + + source_ref: Optional[str] = None + """ + For GitHub-sourced deployments, the git ref as requested at deploy time (branch, + tag, or commit SHA — not resolved to a commit). Omitted for file uploads. + """ + + source_type: Optional[Literal["file", "github"]] = None + """Origin of the deployed source code. + + This is read-only response provenance; `file` indicates an uploaded archive and + `github` indicates a repository fetched by the API. + """ + + source_url: Optional[str] = None + """For GitHub-sourced deployments, the repository URL that was fetched. + + Omitted for file uploads. + """ + status_reason: Optional[str] = None """Status reason""" diff --git a/src/kernel/types/deployment_retrieve_response.py b/src/kernel/types/deployment_retrieve_response.py index addcad4a..2f4cf49e 100644 --- a/src/kernel/types/deployment_retrieve_response.py +++ b/src/kernel/types/deployment_retrieve_response.py @@ -35,6 +35,39 @@ class DeploymentRetrieveResponse(BaseModel): values. """ + source_checksum: Optional[str] = None + """Hex-encoded SHA-256 checksum of the source archive. + + For file uploads, this hashes the uploaded archive; for GitHub-sourced + deployments, this hashes the GitHub archive downloaded by the API. Omitted for + deployments created before this field was recorded. + """ + + source_path: Optional[str] = None + """ + For GitHub-sourced deployments, the subpath within the repository that was used + as the deploy root. Omitted when the repo root was used or for file uploads. + """ + + source_ref: Optional[str] = None + """ + For GitHub-sourced deployments, the git ref as requested at deploy time (branch, + tag, or commit SHA — not resolved to a commit). Omitted for file uploads. + """ + + source_type: Optional[Literal["file", "github"]] = None + """Origin of the deployed source code. + + This is read-only response provenance; `file` indicates an uploaded archive and + `github` indicates a repository fetched by the API. + """ + + source_url: Optional[str] = None + """For GitHub-sourced deployments, the repository URL that was fetched. + + Omitted for file uploads. + """ + status_reason: Optional[str] = None """Status reason""" diff --git a/src/kernel/types/deployment_state_event.py b/src/kernel/types/deployment_state_event.py index dce183a7..64835725 100644 --- a/src/kernel/types/deployment_state_event.py +++ b/src/kernel/types/deployment_state_event.py @@ -35,6 +35,39 @@ class Deployment(BaseModel): values. """ + source_checksum: Optional[str] = None + """Hex-encoded SHA-256 checksum of the source archive. + + For file uploads, this hashes the uploaded archive; for GitHub-sourced + deployments, this hashes the GitHub archive downloaded by the API. Omitted for + deployments created before this field was recorded. + """ + + source_path: Optional[str] = None + """ + For GitHub-sourced deployments, the subpath within the repository that was used + as the deploy root. Omitted when the repo root was used or for file uploads. + """ + + source_ref: Optional[str] = None + """ + For GitHub-sourced deployments, the git ref as requested at deploy time (branch, + tag, or commit SHA — not resolved to a commit). Omitted for file uploads. + """ + + source_type: Optional[Literal["file", "github"]] = None + """Origin of the deployed source code. + + This is read-only response provenance; `file` indicates an uploaded archive and + `github` indicates a repository fetched by the API. + """ + + source_url: Optional[str] = None + """For GitHub-sourced deployments, the repository URL that was fetched. + + Omitted for file uploads. + """ + status_reason: Optional[str] = None """Status reason""" diff --git a/src/kernel/types/extension_list_params.py b/src/kernel/types/extension_list_params.py index bade1423..4c6669a9 100644 --- a/src/kernel/types/extension_list_params.py +++ b/src/kernel/types/extension_list_params.py @@ -11,8 +11,19 @@ class ExtensionListParams(TypedDict, total=False): limit: int """Limit the number of extensions to return.""" + name: str + """Exact-match filter on extension name using the database collation. + + In production, matching is case- and accent-insensitive. During the + default-project migration, unscoped requests prefer a concrete default-project + extension over a legacy unscoped extension with the same name. + """ + offset: int """Offset the number of extensions to return.""" query: str - """Search extensions by name or ID.""" + """Case-insensitive substring match against extension name. + + IDs match by exact value. + """ diff --git a/src/kernel/types/organization/limit_update_params.py b/src/kernel/types/organization/limit_update_params.py index 619eae91..4c85f9c1 100644 --- a/src/kernel/types/organization/limit_update_params.py +++ b/src/kernel/types/organization/limit_update_params.py @@ -10,8 +10,8 @@ class LimitUpdateParams(TypedDict, total=False): default_project_max_concurrent_sessions: Optional[int] - """ - Default maximum concurrent browser sessions for projects without an explicit - override. Set to 0 to remove the default; omit to leave unchanged. Cannot exceed - the organization's concurrent session ceiling. + """Default maximum concurrent browsers for projects without an explicit override. + + Set to 0 to remove the default; omit to leave unchanged. Cannot exceed the + organization's concurrency limit. """ diff --git a/src/kernel/types/organization/org_limits.py b/src/kernel/types/organization/org_limits.py index da9153c1..3d614996 100644 --- a/src/kernel/types/organization/org_limits.py +++ b/src/kernel/types/organization/org_limits.py @@ -10,7 +10,7 @@ class OrgLimits(BaseModel): default_project_max_concurrent_sessions: Optional[int] = None """ - Default maximum concurrent browser sessions applied to every project that has no + Default maximum concurrent browsers applied to every project that has no explicit per-project override. Null means no org-level default, so such projects are uncapped (only the org-wide limit applies). Applies to existing and newly created projects. @@ -18,7 +18,8 @@ class OrgLimits(BaseModel): max_concurrent_sessions: Optional[int] = None """ - The organization's effective concurrent browser session ceiling, from its plan - or an override. Read-only and shared across all projects in the org; a + The organization's effective concurrency limit — the maximum browsers running at + once, covering both on-demand sessions and browser pool reservations — from its + plan or an override. Read-only and shared across all projects in the org; a per-project default cannot exceed it. """ diff --git a/src/kernel/types/profile_create_params.py b/src/kernel/types/profile_create_params.py index bca1e17d..8d1c2f4f 100644 --- a/src/kernel/types/profile_create_params.py +++ b/src/kernel/types/profile_create_params.py @@ -9,4 +9,9 @@ class ProfileCreateParams(TypedDict, total=False): name: str - """Optional name of the profile. Must be unique within the project.""" + """Optional name of the profile. + + Must be unique within the logical project; during the default-project migration, + unscoped profiles and profiles in the org default project are treated as the + same project. + """ diff --git a/src/kernel/types/profile_list_params.py b/src/kernel/types/profile_list_params.py index 4218f5bc..5a572f6b 100644 --- a/src/kernel/types/profile_list_params.py +++ b/src/kernel/types/profile_list_params.py @@ -11,8 +11,16 @@ class ProfileListParams(TypedDict, total=False): limit: int """Limit the number of profiles to return.""" + name: str + """Exact-match filter on profile name using the database collation. + + In production, matching is case- and accent-insensitive. During the + default-project migration, unscoped requests prefer a concrete default-project + profile over a legacy unscoped profile with the same name. + """ + offset: int """Offset the number of profiles to return.""" query: str - """Search profiles by name or ID.""" + """Case-insensitive substring match against profile name or ID.""" diff --git a/src/kernel/types/profile_update_params.py b/src/kernel/types/profile_update_params.py new file mode 100644 index 00000000..bd0165b7 --- /dev/null +++ b/src/kernel/types/profile_update_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ProfileUpdateParams"] + + +class ProfileUpdateParams(TypedDict, total=False): + name: Required[str] + """New profile name. + + Must be unique within the logical project; during the default-project migration, + unscoped profiles and profiles in the org default project are treated as the + same project. + """ diff --git a/src/kernel/types/project_list_params.py b/src/kernel/types/project_list_params.py index 9e740e60..dd307d17 100644 --- a/src/kernel/types/project_list_params.py +++ b/src/kernel/types/project_list_params.py @@ -11,6 +11,12 @@ class ProjectListParams(TypedDict, total=False): limit: int """Maximum number of results to return""" + name: str + """Exact-match filter on project name using the database collation. + + In production, matching is case- and accent-insensitive. + """ + offset: int """Number of results to skip""" diff --git a/src/kernel/types/projects/limit_update_params.py b/src/kernel/types/projects/limit_update_params.py index 387b4c64..8bfb2775 100644 --- a/src/kernel/types/projects/limit_update_params.py +++ b/src/kernel/types/projects/limit_update_params.py @@ -16,13 +16,15 @@ class LimitUpdateParams(TypedDict, total=False): """ max_concurrent_sessions: Optional[int] - """Maximum concurrent browser sessions for this project. - - Set to 0 to remove the cap; omit to leave unchanged. + """ + Maximum concurrent browsers for this project, covering both on-demand sessions + and browser pool reservations. Set to 0 to remove the cap; omit to leave + unchanged. """ max_pooled_sessions: Optional[int] - """Maximum pooled sessions capacity for this project. + """Deprecated: pooled browsers now count toward `max_concurrent_sessions`. - Set to 0 to remove the cap; omit to leave unchanged. + Requests that set this field are rejected with a 400 once the unified + concurrency limit is enabled for your organization. """ diff --git a/src/kernel/types/projects/project_limits.py b/src/kernel/types/projects/project_limits.py index 99868fc8..a7f5cd74 100644 --- a/src/kernel/types/projects/project_limits.py +++ b/src/kernel/types/projects/project_limits.py @@ -15,13 +15,14 @@ class ProjectLimits(BaseModel): """ max_concurrent_sessions: Optional[int] = None - """Maximum concurrent browser sessions for this project. - - Null means no project-level cap. + """ + Maximum concurrent browsers for this project, covering both on-demand sessions + (`browsers.create()`) and browser pool reservations. Null means no project-level + cap. """ max_pooled_sessions: Optional[int] = None - """Maximum pooled sessions capacity for this project. + """Deprecated: pooled browsers now count toward `max_concurrent_sessions`. - Null means no project-level cap. + Always null once the unified concurrency limit is enabled for your organization. """ diff --git a/src/kernel/types/proxy_list_params.py b/src/kernel/types/proxy_list_params.py index 75c5f133..1c7b30e6 100644 --- a/src/kernel/types/proxy_list_params.py +++ b/src/kernel/types/proxy_list_params.py @@ -11,8 +11,18 @@ class ProxyListParams(TypedDict, total=False): limit: int """Limit the number of proxies to return.""" + name: str + """Exact-match filter on proxy name using the database collation. + + In production, matching is case- and accent-insensitive. Names are not required + to be unique, so multiple proxies may match. + """ + offset: int """Offset the number of proxies to return.""" query: str - """Search proxies by name, host, IP address, or ID.""" + """Case-insensitive substring match against proxy name, host, or IP address. + + IDs match by exact value. + """ diff --git a/src/kernel/types/proxy_update_params.py b/src/kernel/types/proxy_update_params.py new file mode 100644 index 00000000..0db118a4 --- /dev/null +++ b/src/kernel/types/proxy_update_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ProxyUpdateParams"] + + +class ProxyUpdateParams(TypedDict, total=False): + name: Required[str] + """New proxy name. + + Proxy names are trimmed and length-checked only; duplicates are allowed because + proxies are updated by ID, not by name. + """ diff --git a/src/kernel/types/proxy_update_response.py b/src/kernel/types/proxy_update_response.py new file mode 100644 index 00000000..d90c3013 --- /dev/null +++ b/src/kernel/types/proxy_update_response.py @@ -0,0 +1,128 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, TypeAlias + +from .._models import BaseModel + +__all__ = [ + "ProxyUpdateResponse", + "Config", + "ConfigDatacenterProxyConfig", + "ConfigIspProxyConfig", + "ConfigResidentialProxyConfig", + "ConfigMobileProxyConfig", + "ConfigCustomProxyConfig", +] + + +class ConfigDatacenterProxyConfig(BaseModel): + """Configuration for a datacenter proxy.""" + + country: Optional[str] = None + """ISO 3166 country code. Defaults to US if not provided.""" + + +class ConfigIspProxyConfig(BaseModel): + """Configuration for an ISP proxy.""" + + country: Optional[str] = None + """ISO 3166 country code. Defaults to US if not provided.""" + + +class ConfigResidentialProxyConfig(BaseModel): + """Configuration for residential proxies.""" + + asn: Optional[str] = None + """Autonomous system number. See https://bgp.potaroo.net/cidr/autnums.html""" + + city: Optional[str] = None + """City name (no spaces, e.g. + + `sanfrancisco`). If provided, `country` must also be provided. + """ + + country: Optional[str] = None + """ISO 3166 country code.""" + + os: Optional[Literal["windows", "macos", "android"]] = None + """Operating system of the residential device.""" + + state: Optional[str] = None + """Two-letter state code.""" + + zip: Optional[str] = None + """US ZIP code.""" + + +class ConfigMobileProxyConfig(BaseModel): + """Configuration for mobile proxies.""" + + city: Optional[str] = None + """Provider city alias. Mobile carrier routing can make observed geo vary.""" + + country: Optional[str] = None + """ISO 3166 country code""" + + state: Optional[str] = None + """US-only state code. Mobile carrier routing can make observed geo vary.""" + + +class ConfigCustomProxyConfig(BaseModel): + """Configuration for a custom proxy (e.g., private proxy server).""" + + host: str + """Proxy host address or IP.""" + + port: int + """Proxy port.""" + + has_password: Optional[bool] = None + """Whether the proxy has a password.""" + + username: Optional[str] = None + """Username for proxy authentication.""" + + +Config: TypeAlias = Union[ + ConfigDatacenterProxyConfig, + ConfigIspProxyConfig, + ConfigResidentialProxyConfig, + ConfigMobileProxyConfig, + ConfigCustomProxyConfig, +] + + +class ProxyUpdateResponse(BaseModel): + """Configuration for routing traffic through a proxy.""" + + type: Literal["datacenter", "isp", "residential", "mobile", "custom"] + """Proxy type to use. + + In terms of quality for avoiding bot-detection, from best to worst: `mobile` > + `residential` > `isp` > `datacenter`. + """ + + id: Optional[str] = None + + bypass_hosts: Optional[List[str]] = None + """Hostnames that should bypass the parent proxy and connect directly.""" + + config: Optional[Config] = None + """Configuration specific to the selected proxy `type`.""" + + ip_address: Optional[str] = None + """IP address that the proxy uses when making requests.""" + + last_checked: Optional[datetime] = None + """Timestamp of the last health check performed on this proxy.""" + + name: Optional[str] = None + """Readable name of the proxy.""" + + protocol: Optional[Literal["http", "https"]] = None + """Protocol to use for the proxy connection.""" + + status: Optional[Literal["available", "unavailable"]] = None + """Current health status of the proxy.""" diff --git a/tests/api_resources/test_api_keys.py b/tests/api_resources/test_api_keys.py index 5fdb5dc6..03d1ed8e 100644 --- a/tests/api_resources/test_api_keys.py +++ b/tests/api_resources/test_api_keys.py @@ -174,6 +174,7 @@ def test_method_list_with_all_params(self, client: Kernel) -> None: api_key = client.api_keys.list( include_deleted=True, limit=100, + name="name", offset=0, query="query", sort_by="created_at", @@ -457,6 +458,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> N api_key = await async_client.api_keys.list( include_deleted=True, limit=100, + name="name", offset=0, query="query", sort_by="created_at", diff --git a/tests/api_resources/test_audit_logs.py b/tests/api_resources/test_audit_logs.py index 47193f05..7a8ebe41 100644 --- a/tests/api_resources/test_audit_logs.py +++ b/tests/api_resources/test_audit_logs.py @@ -43,7 +43,7 @@ def test_method_list_with_all_params(self, client: Kernel) -> None: end=parse_datetime("2026-01-02T00:00:00Z"), start=parse_datetime("2026-01-01T00:00:00Z"), auth_strategy="auth_strategy", - exclude_method="exclude_method", + exclude_method=["string"], limit=1, method="method", page_token="page_token", @@ -103,7 +103,7 @@ def test_method_export_chunk_with_all_params(self, client: Kernel, respx_mock: M start=parse_datetime("2026-01-01T00:00:00Z"), auth_strategy="auth_strategy", cursor="cursor", - exclude_method="exclude_method", + exclude_method=["string"], format="jsonl", limit=1, method="method", @@ -170,7 +170,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> N end=parse_datetime("2026-01-02T00:00:00Z"), start=parse_datetime("2026-01-01T00:00:00Z"), auth_strategy="auth_strategy", - exclude_method="exclude_method", + exclude_method=["string"], limit=1, method="method", page_token="page_token", @@ -230,7 +230,7 @@ async def test_method_export_chunk_with_all_params(self, async_client: AsyncKern start=parse_datetime("2026-01-01T00:00:00Z"), auth_strategy="auth_strategy", cursor="cursor", - exclude_method="exclude_method", + exclude_method=["string"], format="jsonl", limit=1, method="method", diff --git a/tests/api_resources/test_browser_pools.py b/tests/api_resources/test_browser_pools.py index b7ca39a4..6f79fc8b 100644 --- a/tests/api_resources/test_browser_pools.py +++ b/tests/api_resources/test_browser_pools.py @@ -218,6 +218,7 @@ def test_method_list(self, client: Kernel) -> None: def test_method_list_with_all_params(self, client: Kernel) -> None: browser_pool = client.browser_pools.list( limit=1, + name="name", offset=0, query="query", ) @@ -654,6 +655,7 @@ async def test_method_list(self, async_client: AsyncKernel) -> None: async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: browser_pool = await async_client.browser_pools.list( limit=1, + name="name", offset=0, query="query", ) diff --git a/tests/api_resources/test_extensions.py b/tests/api_resources/test_extensions.py index cda54a2d..ace8ec6b 100644 --- a/tests/api_resources/test_extensions.py +++ b/tests/api_resources/test_extensions.py @@ -41,6 +41,7 @@ def test_method_list(self, client: Kernel) -> None: def test_method_list_with_all_params(self, client: Kernel) -> None: extension = client.extensions.list( limit=1, + name="name", offset=0, query="query", ) @@ -317,6 +318,7 @@ async def test_method_list(self, async_client: AsyncKernel) -> None: async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: extension = await async_client.extensions.list( limit=1, + name="name", offset=0, query="query", ) diff --git a/tests/api_resources/test_profiles.py b/tests/api_resources/test_profiles.py index 296593ea..683a3ce2 100644 --- a/tests/api_resources/test_profiles.py +++ b/tests/api_resources/test_profiles.py @@ -104,6 +104,52 @@ def test_path_params_retrieve(self, client: Kernel) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update(self, client: Kernel) -> None: + profile = client.profiles.update( + id_or_name="id_or_name", + name="my-renamed-profile", + ) + assert_matches_type(Profile, profile, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_update(self, client: Kernel) -> None: + response = client.profiles.with_raw_response.update( + id_or_name="id_or_name", + name="my-renamed-profile", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = response.parse() + assert_matches_type(Profile, profile, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_update(self, client: Kernel) -> None: + with client.profiles.with_streaming_response.update( + id_or_name="id_or_name", + name="my-renamed-profile", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = response.parse() + assert_matches_type(Profile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_update(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.profiles.with_raw_response.update( + id_or_name="", + name="my-renamed-profile", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_list(self, client: Kernel) -> None: @@ -115,6 +161,7 @@ def test_method_list(self, client: Kernel) -> None: def test_method_list_with_all_params(self, client: Kernel) -> None: profile = client.profiles.list( limit=1, + name="name", offset=0, query="query", ) @@ -318,6 +365,52 @@ async def test_path_params_retrieve(self, async_client: AsyncKernel) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update(self, async_client: AsyncKernel) -> None: + profile = await async_client.profiles.update( + id_or_name="id_or_name", + name="my-renamed-profile", + ) + assert_matches_type(Profile, profile, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_update(self, async_client: AsyncKernel) -> None: + response = await async_client.profiles.with_raw_response.update( + id_or_name="id_or_name", + name="my-renamed-profile", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + profile = await response.parse() + assert_matches_type(Profile, profile, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_update(self, async_client: AsyncKernel) -> None: + async with async_client.profiles.with_streaming_response.update( + id_or_name="id_or_name", + name="my-renamed-profile", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + profile = await response.parse() + assert_matches_type(Profile, profile, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_update(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + await async_client.profiles.with_raw_response.update( + id_or_name="", + name="my-renamed-profile", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_list(self, async_client: AsyncKernel) -> None: @@ -329,6 +422,7 @@ async def test_method_list(self, async_client: AsyncKernel) -> None: async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: profile = await async_client.profiles.list( limit=1, + name="name", offset=0, query="query", ) diff --git a/tests/api_resources/test_projects.py b/tests/api_resources/test_projects.py index bb301454..007353fe 100644 --- a/tests/api_resources/test_projects.py +++ b/tests/api_resources/test_projects.py @@ -157,6 +157,7 @@ def test_method_list(self, client: Kernel) -> None: def test_method_list_with_all_params(self, client: Kernel) -> None: project = client.projects.list( limit=100, + name="name", offset=0, query="query", ) @@ -371,6 +372,7 @@ async def test_method_list(self, async_client: AsyncKernel) -> None: async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: project = await async_client.projects.list( limit=100, + name="name", offset=0, query="query", ) diff --git a/tests/api_resources/test_proxies.py b/tests/api_resources/test_proxies.py index 29df16e4..cbe6e355 100644 --- a/tests/api_resources/test_proxies.py +++ b/tests/api_resources/test_proxies.py @@ -13,6 +13,7 @@ ProxyListResponse, ProxyCheckResponse, ProxyCreateResponse, + ProxyUpdateResponse, ProxyRetrieveResponse, ) from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination @@ -111,6 +112,52 @@ def test_path_params_retrieve(self, client: Kernel) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update(self, client: Kernel) -> None: + proxy = client.proxies.update( + id="id", + name="my-renamed-proxy", + ) + assert_matches_type(ProxyUpdateResponse, proxy, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_update(self, client: Kernel) -> None: + response = client.proxies.with_raw_response.update( + id="id", + name="my-renamed-proxy", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + proxy = response.parse() + assert_matches_type(ProxyUpdateResponse, proxy, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_update(self, client: Kernel) -> None: + with client.proxies.with_streaming_response.update( + id="id", + name="my-renamed-proxy", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + proxy = response.parse() + assert_matches_type(ProxyUpdateResponse, proxy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_update(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.proxies.with_raw_response.update( + id="", + name="my-renamed-proxy", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_list(self, client: Kernel) -> None: @@ -122,6 +169,7 @@ def test_method_list(self, client: Kernel) -> None: def test_method_list_with_all_params(self, client: Kernel) -> None: proxy = client.proxies.list( limit=1, + name="name", offset=0, query="query", ) @@ -336,6 +384,52 @@ async def test_path_params_retrieve(self, async_client: AsyncKernel) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update(self, async_client: AsyncKernel) -> None: + proxy = await async_client.proxies.update( + id="id", + name="my-renamed-proxy", + ) + assert_matches_type(ProxyUpdateResponse, proxy, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_update(self, async_client: AsyncKernel) -> None: + response = await async_client.proxies.with_raw_response.update( + id="id", + name="my-renamed-proxy", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + proxy = await response.parse() + assert_matches_type(ProxyUpdateResponse, proxy, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_update(self, async_client: AsyncKernel) -> None: + async with async_client.proxies.with_streaming_response.update( + id="id", + name="my-renamed-proxy", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + proxy = await response.parse() + assert_matches_type(ProxyUpdateResponse, proxy, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_update(self, async_client: AsyncKernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.proxies.with_raw_response.update( + id="", + name="my-renamed-proxy", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_list(self, async_client: AsyncKernel) -> None: @@ -347,6 +441,7 @@ async def test_method_list(self, async_client: AsyncKernel) -> None: async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: proxy = await async_client.proxies.list( limit=1, + name="name", offset=0, query="query", )