diff --git a/.release-please-manifest.json b/.release-please-manifest.json index a8124647..a579a434 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.98.0" + ".": "0.99.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index a867372d..5fe5772a 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 147 +configured_endpoints: 158 diff --git a/CHANGELOG.md b/CHANGELOG.md index 992c5f68..2c0c8bf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.99.0](https://github.com/kernel/kernel-python-sdk/compare/v0.98.0...v0.99.0) (2026-09-04) + + +### Features + +* Expose OTLP destination delivery health ([9ab1d58](https://github.com/kernel/kernel-python-sdk/commit/9ab1d583d7bb4dabba5a640883dda9f2ac248f18)) +* Repair Vault SDK custom-code seals ([645ce00](https://github.com/kernel/kernel-python-sdk/commit/645ce00d68172a323d11b7e4dd4f3997cc287fe0)) + ## [0.98.0](https://github.com/kernel/kernel-python-sdk/compare/v0.97.0...v0.98.0) (2026-09-02) diff --git a/api.md b/api.md index 4a09a5d9..797c5d9c 100644 --- a/api.md +++ b/api.md @@ -126,6 +126,7 @@ from kernel.types import ( BrowserUsage, Profile, Tags, + VaultReference, BrowserCreateResponse, BrowserRetrieveResponse, BrowserUpdateResponse, @@ -486,6 +487,52 @@ Methods: - client.browser_pools.flush(id_or_name) -> None - client.browser_pools.release(id_or_name, \*\*params) -> None +# Vaults + +Types: + +```python +from kernel.types import Vault +``` + +Methods: + +- client.vaults.retrieve(id_or_name) -> Vault +- client.vaults.list(\*\*params) -> SyncOffsetPagination[Vault] +- client.vaults.delete(id_or_name) -> None +- client.vaults.upsert(\*\*params) -> Vault + +## Items + +Types: + +```python +from kernel.types.vaults import ( + AgentcardCheckoutAuthorization, + CardVaultItemSpec, + CardVaultItemState, + VaultCardAliases, + VaultItem, + VaultItemAction, + VaultItemEvent, + VaultPaymentMethod, + WalletVaultItemSpec, + WalletVaultItemState, + ItemListResponse, + ItemEventsResponse, +) +``` + +Methods: + +- client.vaults.items.retrieve(key, \*, id_or_name, \*\*params) -> VaultItem +- client.vaults.items.update(key, \*, id_or_name, \*\*params) -> VaultItem +- client.vaults.items.list(id_or_name) -> ItemListResponse +- client.vaults.items.delete(key, \*, id_or_name) -> None +- client.vaults.items.events(key, \*, id_or_name, \*\*params) -> ItemEventsResponse +- client.vaults.items.perform_operation(key, \*, id_or_name, \*\*params) -> VaultItem +- client.vaults.items.upsert(key, \*, id_or_name, \*\*params) -> VaultItem + # Credentials Types: diff --git a/pyproject.toml b/pyproject.toml index fbe3ab05..dc940a7b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kernel" -version = "0.98.0" +version = "0.99.0" description = "The official Python library for the kernel API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/kernel/_client.py b/src/kernel/_client.py index 2c06cb04..acdb7357 100644 --- a/src/kernel/_client.py +++ b/src/kernel/_client.py @@ -50,6 +50,7 @@ from .resources import ( apps, auth, + vaults, proxies, api_keys, browsers, @@ -76,6 +77,7 @@ from .resources.deployments import DeploymentsResource, AsyncDeploymentsResource from .resources.invocations import InvocationsResource, AsyncInvocationsResource from .resources.browser_pools import BrowserPoolsResource, AsyncBrowserPoolsResource + from .resources.vaults.vaults import VaultsResource, AsyncVaultsResource from .resources.browsers.browsers import BrowsersResource, AsyncBrowsersResource from .resources.projects.projects import ProjectsResource, AsyncProjectsResource from .resources.telemetry.telemetry import TelemetryResource, AsyncTelemetryResource @@ -279,6 +281,12 @@ def browser_pools(self) -> BrowserPoolsResource: return BrowserPoolsResource(self) + @cached_property + def vaults(self) -> VaultsResource: + from .resources.vaults import VaultsResource + + return VaultsResource(self) + @cached_property def credentials(self) -> CredentialsResource: """Create and manage credentials for authentication.""" @@ -662,6 +670,12 @@ def browser_pools(self) -> AsyncBrowserPoolsResource: return AsyncBrowserPoolsResource(self) + @cached_property + def vaults(self) -> AsyncVaultsResource: + from .resources.vaults import AsyncVaultsResource + + return AsyncVaultsResource(self) + @cached_property def credentials(self) -> AsyncCredentialsResource: """Create and manage credentials for authentication.""" @@ -949,6 +963,12 @@ def browser_pools(self) -> browser_pools.BrowserPoolsResourceWithRawResponse: return BrowserPoolsResourceWithRawResponse(self._client.browser_pools) + @cached_property + def vaults(self) -> vaults.VaultsResourceWithRawResponse: + from .resources.vaults import VaultsResourceWithRawResponse + + return VaultsResourceWithRawResponse(self._client.vaults) + @cached_property def credentials(self) -> credentials.CredentialsResourceWithRawResponse: """Create and manage credentials for authentication.""" @@ -1076,6 +1096,12 @@ def browser_pools(self) -> browser_pools.AsyncBrowserPoolsResourceWithRawRespons return AsyncBrowserPoolsResourceWithRawResponse(self._client.browser_pools) + @cached_property + def vaults(self) -> vaults.AsyncVaultsResourceWithRawResponse: + from .resources.vaults import AsyncVaultsResourceWithRawResponse + + return AsyncVaultsResourceWithRawResponse(self._client.vaults) + @cached_property def credentials(self) -> credentials.AsyncCredentialsResourceWithRawResponse: """Create and manage credentials for authentication.""" @@ -1203,6 +1229,12 @@ def browser_pools(self) -> browser_pools.BrowserPoolsResourceWithStreamingRespon return BrowserPoolsResourceWithStreamingResponse(self._client.browser_pools) + @cached_property + def vaults(self) -> vaults.VaultsResourceWithStreamingResponse: + from .resources.vaults import VaultsResourceWithStreamingResponse + + return VaultsResourceWithStreamingResponse(self._client.vaults) + @cached_property def credentials(self) -> credentials.CredentialsResourceWithStreamingResponse: """Create and manage credentials for authentication.""" @@ -1330,6 +1362,12 @@ def browser_pools(self) -> browser_pools.AsyncBrowserPoolsResourceWithStreamingR return AsyncBrowserPoolsResourceWithStreamingResponse(self._client.browser_pools) + @cached_property + def vaults(self) -> vaults.AsyncVaultsResourceWithStreamingResponse: + from .resources.vaults import AsyncVaultsResourceWithStreamingResponse + + return AsyncVaultsResourceWithStreamingResponse(self._client.vaults) + @cached_property def credentials(self) -> credentials.AsyncCredentialsResourceWithStreamingResponse: """Create and manage credentials for authentication.""" diff --git a/src/kernel/_version.py b/src/kernel/_version.py index 4adaa91f..18073be8 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.98.0" # x-release-please-version +__version__ = "0.99.0" # x-release-please-version diff --git a/src/kernel/resources/__init__.py b/src/kernel/resources/__init__.py index c6496534..5bc0849c 100644 --- a/src/kernel/resources/__init__.py +++ b/src/kernel/resources/__init__.py @@ -16,6 +16,14 @@ AuthResourceWithStreamingResponse, AsyncAuthResourceWithStreamingResponse, ) +from .vaults import ( + VaultsResource, + AsyncVaultsResource, + VaultsResourceWithRawResponse, + AsyncVaultsResourceWithRawResponse, + VaultsResourceWithStreamingResponse, + AsyncVaultsResourceWithStreamingResponse, +) from .proxies import ( ProxiesResource, AsyncProxiesResource, @@ -204,6 +212,12 @@ "AsyncBrowserPoolsResourceWithRawResponse", "BrowserPoolsResourceWithStreamingResponse", "AsyncBrowserPoolsResourceWithStreamingResponse", + "VaultsResource", + "AsyncVaultsResource", + "VaultsResourceWithRawResponse", + "AsyncVaultsResourceWithRawResponse", + "VaultsResourceWithStreamingResponse", + "AsyncVaultsResourceWithStreamingResponse", "CredentialsResource", "AsyncCredentialsResource", "CredentialsResourceWithRawResponse", diff --git a/src/kernel/resources/browsers/browsers.py b/src/kernel/resources/browsers/browsers.py index d703df24..219dd462 100644 --- a/src/kernel/resources/browsers/browsers.py +++ b/src/kernel/resources/browsers/browsers.py @@ -97,6 +97,7 @@ from ...types.tags_param import TagsParam from ...types.browser_curl_response import BrowserCurlResponse from ...types.browser_list_response import BrowserListResponse +from ...types.vault_reference_param import VaultReferenceParam from ...lib.browser_routing.raw_http import ( stream_via_browser_route, request_via_browser_route, @@ -201,6 +202,7 @@ def create( tags: TagsParam | Omit = omit, telemetry: Optional[browser_create_params.Telemetry] | Omit = omit, timeout_seconds: int | Omit = omit, + vaults: Iterable[VaultReferenceParam] | Omit = omit, viewport: BrowserViewport | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -284,6 +286,9 @@ def create( check for inactivity every 5 seconds, so the actual timeout behavior you will see is +/- 5 seconds around the specified value. + vaults: Project-scoped vaults to link to the browser session. Links are immutable after + creation. + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (1920x1080@25). For GPU images, the default is 1920x1080@60. Arbitrary viewport dimensions and refresh rates are accepted. @@ -327,6 +332,7 @@ def create( "tags": tags, "telemetry": telemetry, "timeout_seconds": timeout_seconds, + "vaults": vaults, "viewport": viewport, }, browser_create_params.BrowserCreateParams, @@ -826,6 +832,7 @@ async def create( tags: TagsParam | Omit = omit, telemetry: Optional[browser_create_params.Telemetry] | Omit = omit, timeout_seconds: int | Omit = omit, + vaults: Iterable[VaultReferenceParam] | Omit = omit, viewport: BrowserViewport | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -909,6 +916,9 @@ async def create( check for inactivity every 5 seconds, so the actual timeout behavior you will see is +/- 5 seconds around the specified value. + vaults: Project-scoped vaults to link to the browser session. Links are immutable after + creation. + viewport: Initial browser window size in pixels with optional refresh rate. If omitted, image defaults apply (1920x1080@25). For GPU images, the default is 1920x1080@60. Arbitrary viewport dimensions and refresh rates are accepted. @@ -952,6 +962,7 @@ async def create( "tags": tags, "telemetry": telemetry, "timeout_seconds": timeout_seconds, + "vaults": vaults, "viewport": viewport, }, browser_create_params.BrowserCreateParams, diff --git a/src/kernel/resources/config_registry/config_registry.py b/src/kernel/resources/config_registry/config_registry.py index e5aa40d6..0b9d1824 100644 --- a/src/kernel/resources/config_registry/config_registry.py +++ b/src/kernel/resources/config_registry/config_registry.py @@ -78,12 +78,12 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> SyncOffsetPagination[RecommendationSummary]: """ - Lists unique domains previously analyzed by the selected project with their - current domain-level recommendations. + Lists unique exact targets previously analyzed by the selected project with the + recommendation produced by each target's latest analysis. Args: - search: Case-insensitive domain search. Full URLs are reduced to their registrable - domain. + search: Case-insensitive substring search over normalized targets, including domain, + subdomain, and path. extra_headers: Send extra headers @@ -252,12 +252,12 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AsyncPaginator[RecommendationSummary, AsyncOffsetPagination[RecommendationSummary]]: """ - Lists unique domains previously analyzed by the selected project with their - current domain-level recommendations. + Lists unique exact targets previously analyzed by the selected project with the + recommendation produced by each target's latest analysis. Args: - search: Case-insensitive domain search. Full URLs are reduced to their registrable - domain. + search: Case-insensitive substring search over normalized targets, including domain, + subdomain, and path. extra_headers: Send extra headers diff --git a/src/kernel/resources/vaults/__init__.py b/src/kernel/resources/vaults/__init__.py new file mode 100644 index 00000000..a019b7ee --- /dev/null +++ b/src/kernel/resources/vaults/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .items import ( + ItemsResource, + AsyncItemsResource, + ItemsResourceWithRawResponse, + AsyncItemsResourceWithRawResponse, + ItemsResourceWithStreamingResponse, + AsyncItemsResourceWithStreamingResponse, +) +from .vaults import ( + VaultsResource, + AsyncVaultsResource, + VaultsResourceWithRawResponse, + AsyncVaultsResourceWithRawResponse, + VaultsResourceWithStreamingResponse, + AsyncVaultsResourceWithStreamingResponse, +) + +__all__ = [ + "ItemsResource", + "AsyncItemsResource", + "ItemsResourceWithRawResponse", + "AsyncItemsResourceWithRawResponse", + "ItemsResourceWithStreamingResponse", + "AsyncItemsResourceWithStreamingResponse", + "VaultsResource", + "AsyncVaultsResource", + "VaultsResourceWithRawResponse", + "AsyncVaultsResourceWithRawResponse", + "VaultsResourceWithStreamingResponse", + "AsyncVaultsResourceWithStreamingResponse", +] diff --git a/src/kernel/resources/vaults/items.py b/src/kernel/resources/vaults/items.py new file mode 100644 index 00000000..17bef3c6 --- /dev/null +++ b/src/kernel/resources/vaults/items.py @@ -0,0 +1,928 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Any, List, cast +from typing_extensions import Literal, overload + +import httpx + +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._utils import path_template, required_args, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.vaults import ( + item_events_params, + item_update_params, + item_upsert_params, + item_retrieve_params, + item_perform_operation_params, +) +from ...types.vaults.vault_item import VaultItem +from ...types.vaults.item_list_response import ItemListResponse +from ...types.vaults.item_events_response import ItemEventsResponse +from ...types.vaults.card_vault_item_spec_param import CardVaultItemSpecParam +from ...types.vaults.wallet_vault_item_spec_param import WalletVaultItemSpecParam + +__all__ = ["ItemsResource", "AsyncItemsResource"] + + +class ItemsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ItemsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return ItemsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ItemsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return ItemsResourceWithStreamingResponse(self) + + def retrieve( + self, + key: str, + *, + id_or_name: str, + expand: List[Literal["payment_methods"]] | Omit = omit, + wait: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VaultItem: + """ + The response advertises operations that are valid in the item's current state + and live data that can be requested through `expand`. Read each operation's + description before using it. Expanded data is fetched from the provider and is + not persisted in the vault item. Requesting an unavailable expansion returns 409 + instead of a partial item. + + Args: + expand: Live fields advertised by `available_expansions` to include in `expanded`. + + wait: Hold for up to this many seconds while the item is pending authorization or + approval. + + 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}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return cast( + VaultItem, + self._get( + path_template("/vaults/{id_or_name}/items/{key}", id_or_name=id_or_name, key=key), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "expand": expand, + "wait": wait, + }, + item_retrieve_params.ItemRetrieveParams, + ), + ), + cast_to=cast(Any, VaultItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + def update( + self, + key: str, + *, + id_or_name: str, + spec: CardVaultItemSpecParam, + # 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, + ) -> VaultItem: + """ + Update a card specification before or between authorizations + + Args: + spec: AgentCard reusable card. Each checkout creates an approval-gated authorization + for spec.merchant / spec.amount. The card stays ready after each authorization. + + 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}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return cast( + VaultItem, + self._patch( + path_template("/vaults/{id_or_name}/items/{key}", id_or_name=id_or_name, key=key), + body=maybe_transform({"spec": spec}, item_update_params.ItemUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, VaultItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + def list( + self, + id_or_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, + ) -> ItemListResponse: + """ + List vault items without secret values + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._get( + path_template("/vaults/{id_or_name}/items", id_or_name=id_or_name), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ItemListResponse, + ) + + def delete( + self, + key: str, + *, + id_or_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, + ) -> None: + """ + Delete a vault item and invalidate its secret value + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/vaults/{id_or_name}/items/{key}", id_or_name=id_or_name, key=key), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def events( + self, + key: str, + *, + id_or_name: str, + after: str | Omit = omit, + wait: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ItemEventsResponse: + """ + List immutable audit events for a vault item + + Args: + after: Return events after this event ID. + + wait: Long-poll for new events for up to this many seconds. + + 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}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return self._get( + path_template("/vaults/{id_or_name}/items/{key}/events", id_or_name=id_or_name, key=key), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "wait": wait, + }, + item_events_params.ItemEventsParams, + ), + ), + cast_to=ItemEventsResponse, + ) + + def perform_operation( + self, + key: str, + *, + id_or_name: str, + type: Literal["authorize"], + # 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, + ) -> VaultItem: + """ + Retrieve the item first and invoke only an operation listed in + `available_operations`, following its natural-language description. Operations + may call an external provider and can return the item's updated state. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return cast( + VaultItem, + self._post( + path_template("/vaults/{id_or_name}/items/{key}/operations", id_or_name=id_or_name, key=key), + body=maybe_transform({"type": type}, item_perform_operation_params.ItemPerformOperationParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, VaultItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + @overload + def upsert( + self, + key: str, + *, + id_or_name: str, + spec: WalletVaultItemSpecParam, + type: Literal["wallet"], + # 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, + ) -> VaultItem: + """ + Create or retrieve an identical vault item by immutable key + + Args: + spec: AgentCard wallet. Mode (sandbox vs live) is fixed by the deployment's AgentCard + credential; there is no per-item test flag. user_id may only reference a user + already enrolled by a wallet in this organization. + + 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 + """ + ... + + @overload + def upsert( + self, + key: str, + *, + id_or_name: str, + spec: CardVaultItemSpecParam, + type: Literal["card"], + # 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, + ) -> VaultItem: + """ + Create or retrieve an identical vault item by immutable key + + Args: + spec: AgentCard reusable card. Each checkout creates an approval-gated authorization + for spec.merchant / spec.amount. The card stays ready after each authorization. + + 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 + """ + ... + + @required_args(["id_or_name", "spec", "type"]) + def upsert( + self, + key: str, + *, + id_or_name: str, + spec: WalletVaultItemSpecParam | CardVaultItemSpecParam, + type: Literal["wallet"] | Literal["card"], + # 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, + ) -> VaultItem: + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return cast( + VaultItem, + self._put( + path_template("/vaults/{id_or_name}/items/{key}", id_or_name=id_or_name, key=key), + body=maybe_transform( + { + "spec": spec, + "type": type, + }, + item_upsert_params.ItemUpsertParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, VaultItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + +class AsyncItemsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncItemsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncItemsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncItemsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return AsyncItemsResourceWithStreamingResponse(self) + + async def retrieve( + self, + key: str, + *, + id_or_name: str, + expand: List[Literal["payment_methods"]] | Omit = omit, + wait: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> VaultItem: + """ + The response advertises operations that are valid in the item's current state + and live data that can be requested through `expand`. Read each operation's + description before using it. Expanded data is fetched from the provider and is + not persisted in the vault item. Requesting an unavailable expansion returns 409 + instead of a partial item. + + Args: + expand: Live fields advertised by `available_expansions` to include in `expanded`. + + wait: Hold for up to this many seconds while the item is pending authorization or + approval. + + 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}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return cast( + VaultItem, + await self._get( + path_template("/vaults/{id_or_name}/items/{key}", id_or_name=id_or_name, key=key), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "expand": expand, + "wait": wait, + }, + item_retrieve_params.ItemRetrieveParams, + ), + ), + cast_to=cast(Any, VaultItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + async def update( + self, + key: str, + *, + id_or_name: str, + spec: CardVaultItemSpecParam, + # 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, + ) -> VaultItem: + """ + Update a card specification before or between authorizations + + Args: + spec: AgentCard reusable card. Each checkout creates an approval-gated authorization + for spec.merchant / spec.amount. The card stays ready after each authorization. + + 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}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return cast( + VaultItem, + await self._patch( + path_template("/vaults/{id_or_name}/items/{key}", id_or_name=id_or_name, key=key), + body=await async_maybe_transform({"spec": spec}, item_update_params.ItemUpdateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, VaultItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + async def list( + self, + id_or_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, + ) -> ItemListResponse: + """ + List vault items without secret values + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._get( + path_template("/vaults/{id_or_name}/items", id_or_name=id_or_name), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ItemListResponse, + ) + + async def delete( + self, + key: str, + *, + id_or_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, + ) -> None: + """ + Delete a vault item and invalidate its secret value + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/vaults/{id_or_name}/items/{key}", id_or_name=id_or_name, key=key), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def events( + self, + key: str, + *, + id_or_name: str, + after: str | Omit = omit, + wait: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ItemEventsResponse: + """ + List immutable audit events for a vault item + + Args: + after: Return events after this event ID. + + wait: Long-poll for new events for up to this many seconds. + + 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}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return await self._get( + path_template("/vaults/{id_or_name}/items/{key}/events", id_or_name=id_or_name, key=key), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "after": after, + "wait": wait, + }, + item_events_params.ItemEventsParams, + ), + ), + cast_to=ItemEventsResponse, + ) + + async def perform_operation( + self, + key: str, + *, + id_or_name: str, + type: Literal["authorize"], + # 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, + ) -> VaultItem: + """ + Retrieve the item first and invoke only an operation listed in + `available_operations`, following its natural-language description. Operations + may call an external provider and can return the item's updated state. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return cast( + VaultItem, + await self._post( + path_template("/vaults/{id_or_name}/items/{key}/operations", id_or_name=id_or_name, key=key), + body=await async_maybe_transform( + {"type": type}, item_perform_operation_params.ItemPerformOperationParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, VaultItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + @overload + async def upsert( + self, + key: str, + *, + id_or_name: str, + spec: WalletVaultItemSpecParam, + type: Literal["wallet"], + # 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, + ) -> VaultItem: + """ + Create or retrieve an identical vault item by immutable key + + Args: + spec: AgentCard wallet. Mode (sandbox vs live) is fixed by the deployment's AgentCard + credential; there is no per-item test flag. user_id may only reference a user + already enrolled by a wallet in this organization. + + 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 + """ + ... + + @overload + async def upsert( + self, + key: str, + *, + id_or_name: str, + spec: CardVaultItemSpecParam, + type: Literal["card"], + # 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, + ) -> VaultItem: + """ + Create or retrieve an identical vault item by immutable key + + Args: + spec: AgentCard reusable card. Each checkout creates an approval-gated authorization + for spec.merchant / spec.amount. The card stays ready after each authorization. + + 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 + """ + ... + + @required_args(["id_or_name", "spec", "type"]) + async def upsert( + self, + key: str, + *, + id_or_name: str, + spec: WalletVaultItemSpecParam | CardVaultItemSpecParam, + type: Literal["wallet"] | Literal["card"], + # 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, + ) -> VaultItem: + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + if not key: + raise ValueError(f"Expected a non-empty value for `key` but received {key!r}") + return cast( + VaultItem, + await self._put( + path_template("/vaults/{id_or_name}/items/{key}", id_or_name=id_or_name, key=key), + body=await async_maybe_transform( + { + "spec": spec, + "type": type, + }, + item_upsert_params.ItemUpsertParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=cast(Any, VaultItem), # Union types cannot be passed in as arguments in the type system + ), + ) + + +class ItemsResourceWithRawResponse: + def __init__(self, items: ItemsResource) -> None: + self._items = items + + self.retrieve = to_raw_response_wrapper( + items.retrieve, + ) + self.update = to_raw_response_wrapper( + items.update, + ) + self.list = to_raw_response_wrapper( + items.list, + ) + self.delete = to_raw_response_wrapper( + items.delete, + ) + self.events = to_raw_response_wrapper( + items.events, + ) + self.perform_operation = to_raw_response_wrapper( + items.perform_operation, + ) + self.upsert = to_raw_response_wrapper( + items.upsert, + ) + + +class AsyncItemsResourceWithRawResponse: + def __init__(self, items: AsyncItemsResource) -> None: + self._items = items + + self.retrieve = async_to_raw_response_wrapper( + items.retrieve, + ) + self.update = async_to_raw_response_wrapper( + items.update, + ) + self.list = async_to_raw_response_wrapper( + items.list, + ) + self.delete = async_to_raw_response_wrapper( + items.delete, + ) + self.events = async_to_raw_response_wrapper( + items.events, + ) + self.perform_operation = async_to_raw_response_wrapper( + items.perform_operation, + ) + self.upsert = async_to_raw_response_wrapper( + items.upsert, + ) + + +class ItemsResourceWithStreamingResponse: + def __init__(self, items: ItemsResource) -> None: + self._items = items + + self.retrieve = to_streamed_response_wrapper( + items.retrieve, + ) + self.update = to_streamed_response_wrapper( + items.update, + ) + self.list = to_streamed_response_wrapper( + items.list, + ) + self.delete = to_streamed_response_wrapper( + items.delete, + ) + self.events = to_streamed_response_wrapper( + items.events, + ) + self.perform_operation = to_streamed_response_wrapper( + items.perform_operation, + ) + self.upsert = to_streamed_response_wrapper( + items.upsert, + ) + + +class AsyncItemsResourceWithStreamingResponse: + def __init__(self, items: AsyncItemsResource) -> None: + self._items = items + + self.retrieve = async_to_streamed_response_wrapper( + items.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + items.update, + ) + self.list = async_to_streamed_response_wrapper( + items.list, + ) + self.delete = async_to_streamed_response_wrapper( + items.delete, + ) + self.events = async_to_streamed_response_wrapper( + items.events, + ) + self.perform_operation = async_to_streamed_response_wrapper( + items.perform_operation, + ) + self.upsert = async_to_streamed_response_wrapper( + items.upsert, + ) diff --git a/src/kernel/resources/vaults/vaults.py b/src/kernel/resources/vaults/vaults.py new file mode 100644 index 00000000..ec33277c --- /dev/null +++ b/src/kernel/resources/vaults/vaults.py @@ -0,0 +1,456 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from .items import ( + ItemsResource, + AsyncItemsResource, + ItemsResourceWithRawResponse, + AsyncItemsResourceWithRawResponse, + ItemsResourceWithStreamingResponse, + AsyncItemsResourceWithStreamingResponse, +) +from ...types import vault_list_params, vault_upsert_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 +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...pagination import SyncOffsetPagination, AsyncOffsetPagination +from ...types.vault import Vault +from ..._base_client import AsyncPaginator, make_request_options + +__all__ = ["VaultsResource", "AsyncVaultsResource"] + + +class VaultsResource(SyncAPIResource): + @cached_property + def items(self) -> ItemsResource: + return ItemsResource(self._client) + + @cached_property + def with_raw_response(self) -> VaultsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return VaultsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> VaultsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return VaultsResourceWithStreamingResponse(self) + + def retrieve( + self, + id_or_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, + ) -> Vault: + """ + Get a vault + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return self._get( + path_template("/vaults/{id_or_name}", id_or_name=id_or_name), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Vault, + ) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncOffsetPagination[Vault]: + """ + List vaults in the current project + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/vaults", + page=SyncOffsetPagination[Vault], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + vault_list_params.VaultListParams, + ), + ), + model=Vault, + ) + + def delete( + self, + id_or_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, + ) -> None: + """ + Delete a vault and invalidate its items + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/vaults/{id_or_name}", id_or_name=id_or_name), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + def upsert( + self, + *, + 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, + ) -> Vault: + """ + Create or retrieve a vault by immutable name + + Args: + name: Immutable name used to create or retrieve the vault. + + 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 + """ + return self._post( + "/vaults", + body=maybe_transform({"name": name}, vault_upsert_params.VaultUpsertParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Vault, + ) + + +class AsyncVaultsResource(AsyncAPIResource): + @cached_property + def items(self) -> AsyncItemsResource: + return AsyncItemsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncVaultsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#accessing-raw-response-data-eg-headers + """ + return AsyncVaultsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncVaultsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/kernel/kernel-python-sdk#with_streaming_response + """ + return AsyncVaultsResourceWithStreamingResponse(self) + + async def retrieve( + self, + id_or_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, + ) -> Vault: + """ + Get a vault + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + return await self._get( + path_template("/vaults/{id_or_name}", id_or_name=id_or_name), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Vault, + ) + + def list( + self, + *, + limit: int | Omit = omit, + offset: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[Vault, AsyncOffsetPagination[Vault]]: + """ + List vaults in the current project + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/vaults", + page=AsyncOffsetPagination[Vault], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "limit": limit, + "offset": offset, + }, + vault_list_params.VaultListParams, + ), + ), + model=Vault, + ) + + async def delete( + self, + id_or_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, + ) -> None: + """ + Delete a vault and invalidate its items + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id_or_name: + raise ValueError(f"Expected a non-empty value for `id_or_name` but received {id_or_name!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/vaults/{id_or_name}", id_or_name=id_or_name), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=NoneType, + ) + + async def upsert( + self, + *, + 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, + ) -> Vault: + """ + Create or retrieve a vault by immutable name + + Args: + name: Immutable name used to create or retrieve the vault. + + 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 + """ + return await self._post( + "/vaults", + body=await async_maybe_transform({"name": name}, vault_upsert_params.VaultUpsertParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=Vault, + ) + + +class VaultsResourceWithRawResponse: + def __init__(self, vaults: VaultsResource) -> None: + self._vaults = vaults + + self.retrieve = to_raw_response_wrapper( + vaults.retrieve, + ) + self.list = to_raw_response_wrapper( + vaults.list, + ) + self.delete = to_raw_response_wrapper( + vaults.delete, + ) + self.upsert = to_raw_response_wrapper( + vaults.upsert, + ) + + @cached_property + def items(self) -> ItemsResourceWithRawResponse: + return ItemsResourceWithRawResponse(self._vaults.items) + + +class AsyncVaultsResourceWithRawResponse: + def __init__(self, vaults: AsyncVaultsResource) -> None: + self._vaults = vaults + + self.retrieve = async_to_raw_response_wrapper( + vaults.retrieve, + ) + self.list = async_to_raw_response_wrapper( + vaults.list, + ) + self.delete = async_to_raw_response_wrapper( + vaults.delete, + ) + self.upsert = async_to_raw_response_wrapper( + vaults.upsert, + ) + + @cached_property + def items(self) -> AsyncItemsResourceWithRawResponse: + return AsyncItemsResourceWithRawResponse(self._vaults.items) + + +class VaultsResourceWithStreamingResponse: + def __init__(self, vaults: VaultsResource) -> None: + self._vaults = vaults + + self.retrieve = to_streamed_response_wrapper( + vaults.retrieve, + ) + self.list = to_streamed_response_wrapper( + vaults.list, + ) + self.delete = to_streamed_response_wrapper( + vaults.delete, + ) + self.upsert = to_streamed_response_wrapper( + vaults.upsert, + ) + + @cached_property + def items(self) -> ItemsResourceWithStreamingResponse: + return ItemsResourceWithStreamingResponse(self._vaults.items) + + +class AsyncVaultsResourceWithStreamingResponse: + def __init__(self, vaults: AsyncVaultsResource) -> None: + self._vaults = vaults + + self.retrieve = async_to_streamed_response_wrapper( + vaults.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + vaults.list, + ) + self.delete = async_to_streamed_response_wrapper( + vaults.delete, + ) + self.upsert = async_to_streamed_response_wrapper( + vaults.upsert, + ) + + @cached_property + def items(self) -> AsyncItemsResourceWithStreamingResponse: + return AsyncItemsResourceWithStreamingResponse(self._vaults.items) diff --git a/src/kernel/types/__init__.py b/src/kernel/types/__init__.py index fffffd45..0310cfbe 100644 --- a/src/kernel/types/__init__.py +++ b/src/kernel/types/__init__.py @@ -6,6 +6,7 @@ from .. import _compat from .tags import Tags as Tags from .proxy import Proxy as Proxy +from .vault import Vault as Vault from .shared import ( LogEvent as LogEvent, AppAction as AppAction, @@ -35,11 +36,13 @@ from .audit_log_entry import AuditLogEntry as AuditLogEntry from .created_api_key import CreatedAPIKey as CreatedAPIKey from .lookup_response import LookupResponse as LookupResponse +from .vault_reference import VaultReference as VaultReference from .analysis_summary import AnalysisSummary as AnalysisSummary from .browser_pool_ref import BrowserPoolRef as BrowserPoolRef from .app_list_response import AppListResponse as AppListResponse from .no_recommendation import NoRecommendation as NoRecommendation from .proxy_list_params import ProxyListParams as ProxyListParams +from .vault_list_params import VaultListParams as VaultListParams from .browser_proxy_mode import BrowserProxyMode as BrowserProxyMode from .proxy_check_params import ProxyCheckParams as ProxyCheckParams from .api_key_list_params import APIKeyListParams as APIKeyListParams @@ -51,6 +54,7 @@ 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 .vault_upsert_params import VaultUpsertParams as VaultUpsertParams from .browser_proxy_config import BrowserProxyConfig as BrowserProxyConfig from .proxy_check_response import ProxyCheckResponse as ProxyCheckResponse from .api_key_create_params import APIKeyCreateParams as APIKeyCreateParams @@ -69,6 +73,7 @@ from .proxy_create_response import ProxyCreateResponse as ProxyCreateResponse from .proxy_update_response import ProxyUpdateResponse as ProxyUpdateResponse from .recommendation_result import RecommendationResult as RecommendationResult +from .vault_reference_param import VaultReferenceParam as VaultReferenceParam from .browser_memory_request import BrowserMemoryRequest as BrowserMemoryRequest from .browser_network_config import BrowserNetworkConfig as BrowserNetworkConfig from .credential_list_params import CredentialListParams as CredentialListParams diff --git a/src/kernel/types/browser_create_params.py b/src/kernel/types/browser_create_params.py index da890722..ab486672 100644 --- a/src/kernel/types/browser_create_params.py +++ b/src/kernel/types/browser_create_params.py @@ -6,6 +6,7 @@ from typing_extensions import Literal, TypedDict from .tags_param import TagsParam +from .vault_reference_param import VaultReferenceParam from .browser_memory_request import BrowserMemoryRequest from .browser_proxy_config_param import BrowserProxyConfigParam from .browser_network_config_param import BrowserNetworkConfigParam @@ -149,6 +150,12 @@ class BrowserCreateParams(TypedDict, total=False): see is +/- 5 seconds around the specified value. """ + vaults: Iterable[VaultReferenceParam] + """Project-scoped vaults to link to the browser session. + + Links are immutable after creation. + """ + viewport: BrowserViewport """ Initial browser window size in pixels with optional refresh rate. If omitted, diff --git a/src/kernel/types/browser_create_response.py b/src/kernel/types/browser_create_response.py index e5f63b6c..678bcbcb 100644 --- a/src/kernel/types/browser_create_response.py +++ b/src/kernel/types/browser_create_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Optional +from typing import Dict, List, Optional from datetime import datetime from typing_extensions import Literal @@ -10,6 +10,7 @@ from .browser_proxy import BrowserProxy from .browser_usage import BrowserUsage from .browser_memory import BrowserMemory +from .vault_reference import VaultReference from .browser_pool_ref import BrowserPoolRef from .browser_network_config import BrowserNetworkConfig from .shared.browser_viewport import BrowserViewport @@ -125,6 +126,15 @@ class BrowserCreateResponse(BaseModel): usage: Optional[BrowserUsage] = None """Session usage metrics.""" + usage_status: Optional[Literal["pending", "ready"]] = None + """Whether final usage billing is still pending or complete. + + Only present for deleted sessions. + """ + + vaults: Optional[List[VaultReference]] = None + """Vaults linked when the browser session was created.""" + viewport: Optional[BrowserViewport] = None """ Initial browser window size in pixels with optional refresh rate. If omitted, diff --git a/src/kernel/types/browser_list_response.py b/src/kernel/types/browser_list_response.py index da294a61..aa281a39 100644 --- a/src/kernel/types/browser_list_response.py +++ b/src/kernel/types/browser_list_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Optional +from typing import Dict, List, Optional from datetime import datetime from typing_extensions import Literal @@ -10,6 +10,7 @@ from .browser_proxy import BrowserProxy from .browser_usage import BrowserUsage from .browser_memory import BrowserMemory +from .vault_reference import VaultReference from .browser_pool_ref import BrowserPoolRef from .browser_network_config import BrowserNetworkConfig from .shared.browser_viewport import BrowserViewport @@ -125,6 +126,15 @@ class BrowserListResponse(BaseModel): usage: Optional[BrowserUsage] = None """Session usage metrics.""" + usage_status: Optional[Literal["pending", "ready"]] = None + """Whether final usage billing is still pending or complete. + + Only present for deleted sessions. + """ + + vaults: Optional[List[VaultReference]] = None + """Vaults linked when the browser session was created.""" + viewport: Optional[BrowserViewport] = None """ Initial browser window size in pixels with optional refresh rate. If omitted, diff --git a/src/kernel/types/browser_pool_acquire_response.py b/src/kernel/types/browser_pool_acquire_response.py index 755f5838..d472b5e0 100644 --- a/src/kernel/types/browser_pool_acquire_response.py +++ b/src/kernel/types/browser_pool_acquire_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Optional +from typing import Dict, List, Optional from datetime import datetime from typing_extensions import Literal @@ -10,6 +10,7 @@ from .browser_proxy import BrowserProxy from .browser_usage import BrowserUsage from .browser_memory import BrowserMemory +from .vault_reference import VaultReference from .browser_pool_ref import BrowserPoolRef from .browser_network_config import BrowserNetworkConfig from .shared.browser_viewport import BrowserViewport @@ -125,6 +126,15 @@ class BrowserPoolAcquireResponse(BaseModel): usage: Optional[BrowserUsage] = None """Session usage metrics.""" + usage_status: Optional[Literal["pending", "ready"]] = None + """Whether final usage billing is still pending or complete. + + Only present for deleted sessions. + """ + + vaults: Optional[List[VaultReference]] = None + """Vaults linked when the browser session was created.""" + viewport: Optional[BrowserViewport] = None """ Initial browser window size in pixels with optional refresh rate. If omitted, diff --git a/src/kernel/types/browser_retrieve_response.py b/src/kernel/types/browser_retrieve_response.py index 332585ca..e6881ab1 100644 --- a/src/kernel/types/browser_retrieve_response.py +++ b/src/kernel/types/browser_retrieve_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Optional +from typing import Dict, List, Optional from datetime import datetime from typing_extensions import Literal @@ -10,6 +10,7 @@ from .browser_proxy import BrowserProxy from .browser_usage import BrowserUsage from .browser_memory import BrowserMemory +from .vault_reference import VaultReference from .browser_pool_ref import BrowserPoolRef from .browser_network_config import BrowserNetworkConfig from .shared.browser_viewport import BrowserViewport @@ -125,6 +126,15 @@ class BrowserRetrieveResponse(BaseModel): usage: Optional[BrowserUsage] = None """Session usage metrics.""" + usage_status: Optional[Literal["pending", "ready"]] = None + """Whether final usage billing is still pending or complete. + + Only present for deleted sessions. + """ + + vaults: Optional[List[VaultReference]] = None + """Vaults linked when the browser session was created.""" + viewport: Optional[BrowserViewport] = None """ Initial browser window size in pixels with optional refresh rate. If omitted, diff --git a/src/kernel/types/browser_update_response.py b/src/kernel/types/browser_update_response.py index 7af24aee..65be1ba3 100644 --- a/src/kernel/types/browser_update_response.py +++ b/src/kernel/types/browser_update_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Dict, Optional +from typing import Dict, List, Optional from datetime import datetime from typing_extensions import Literal @@ -10,6 +10,7 @@ from .browser_proxy import BrowserProxy from .browser_usage import BrowserUsage from .browser_memory import BrowserMemory +from .vault_reference import VaultReference from .browser_pool_ref import BrowserPoolRef from .browser_network_config import BrowserNetworkConfig from .shared.browser_viewport import BrowserViewport @@ -125,6 +126,15 @@ class BrowserUpdateResponse(BaseModel): usage: Optional[BrowserUsage] = None """Session usage metrics.""" + usage_status: Optional[Literal["pending", "ready"]] = None + """Whether final usage billing is still pending or complete. + + Only present for deleted sessions. + """ + + vaults: Optional[List[VaultReference]] = None + """Vaults linked when the browser session was created.""" + viewport: Optional[BrowserViewport] = None """ Initial browser window size in pixels with optional refresh rate. If omitted, diff --git a/src/kernel/types/config_registry_list_params.py b/src/kernel/types/config_registry_list_params.py index 5259e4b7..7277ef4b 100644 --- a/src/kernel/types/config_registry_list_params.py +++ b/src/kernel/types/config_registry_list_params.py @@ -13,9 +13,9 @@ class ConfigRegistryListParams(TypedDict, total=False): offset: int search: str - """Case-insensitive domain search. - - Full URLs are reduced to their registrable domain. + """ + Case-insensitive substring search over normalized targets, including domain, + subdomain, and path. """ sort_by: Literal["target", "analysis_status", "recommended_config", "last_requested_at", "success_rate"] diff --git a/src/kernel/types/invocation_list_browsers_response.py b/src/kernel/types/invocation_list_browsers_response.py index e31194b8..bb9d423d 100644 --- a/src/kernel/types/invocation_list_browsers_response.py +++ b/src/kernel/types/invocation_list_browsers_response.py @@ -10,6 +10,7 @@ from .browser_proxy import BrowserProxy from .browser_usage import BrowserUsage from .browser_memory import BrowserMemory +from .vault_reference import VaultReference from .browser_pool_ref import BrowserPoolRef from .browser_network_config import BrowserNetworkConfig from .shared.browser_viewport import BrowserViewport @@ -125,6 +126,15 @@ class Browser(BaseModel): usage: Optional[BrowserUsage] = None """Session usage metrics.""" + usage_status: Optional[Literal["pending", "ready"]] = None + """Whether final usage billing is still pending or complete. + + Only present for deleted sessions. + """ + + vaults: Optional[List[VaultReference]] = None + """Vaults linked when the browser session was created.""" + viewport: Optional[BrowserViewport] = None """ Initial browser window size in pixels with optional refresh rate. If omitted, diff --git a/src/kernel/types/recommendation_summary.py b/src/kernel/types/recommendation_summary.py index df83ae35..278ba9ef 100644 --- a/src/kernel/types/recommendation_summary.py +++ b/src/kernel/types/recommendation_summary.py @@ -12,16 +12,22 @@ class RecommendationSummary(BaseModel): analysis_id: str - """ID of the most recently requested analysis for this domain.""" + """ID of the most recently requested analysis for this exact target.""" analysis_status: Literal["running", "completed", "failed", "canceled"] - """Lifecycle status of the most recently requested analysis for this domain.""" + """Lifecycle status of the most recently requested analysis for this exact target.""" last_requested_at: datetime - """Most recent time the selected project requested an analysis for this domain.""" + """ + Most recent time the selected project requested an analysis for this exact + target. + """ recommendation: Optional[Recommendation] = None - """Current domain-level recommendation. Null when no eligible knowledge exists.""" + """Recommendation produced by the latest analysis. + + Null when that analysis did not produce one. + """ recommended_config_label: Optional[str] = None """Display label for the recommended browser configuration.""" @@ -29,8 +35,11 @@ class RecommendationSummary(BaseModel): success_rate: Optional[float] = None """Success rate for the recommended configuration. - Null when no eligible knowledge exists. + Null when the latest analysis did not produce one. """ target: str - """Registrable domain previously analyzed by the selected project.""" + """ + Normalized exact target previously analyzed by the selected project, including + scheme, host, port, and path. + """ diff --git a/src/kernel/types/telemetry/otlp_destination.py b/src/kernel/types/telemetry/otlp_destination.py index 0afe6ae8..293c2497 100644 --- a/src/kernel/types/telemetry/otlp_destination.py +++ b/src/kernel/types/telemetry/otlp_destination.py @@ -16,6 +16,13 @@ class OtlpDestination(BaseModel): id: str + consecutive_failures: int + """ + Failed deliveries since the last success, as observed by the relay process that + wrote the latest outcome. Zero means the most recently recorded outcome + succeeded. + """ + created_at: datetime endpoint: str @@ -39,3 +46,21 @@ class OtlpDestination(BaseModel): updated_at: datetime description: Optional[str] = None + + last_error: Optional[str] = None + """Sanitized class of the delivery failure recorded at `last_error_at`. + + It is retained after a later success, so its presence does not mean the + destination is currently failing. Response bodies, endpoint URLs, credentials, + and raw transport errors are never returned. + """ + + last_error_at: Optional[datetime] = None + """Timestamp of the most recent failed delivery. + + It is retained after a later success, so it can predate `last_export_at`. Read + `consecutive_failures` to tell whether the destination is currently failing. + """ + + last_export_at: Optional[datetime] = None + """Timestamp of the most recent successful delivery. Moves only on success.""" diff --git a/src/kernel/types/vault.py b/src/kernel/types/vault.py new file mode 100644 index 00000000..210edfbe --- /dev/null +++ b/src/kernel/types/vault.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from datetime import datetime + +from .._models import BaseModel + +__all__ = ["Vault"] + + +class Vault(BaseModel): + id: str + + created_at: datetime + + name: str + """Immutable name assigned when the vault is created.""" + + updated_at: datetime diff --git a/src/kernel/types/vault_list_params.py b/src/kernel/types/vault_list_params.py new file mode 100644 index 00000000..7530bc28 --- /dev/null +++ b/src/kernel/types/vault_list_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["VaultListParams"] + + +class VaultListParams(TypedDict, total=False): + limit: int + + offset: int diff --git a/src/kernel/types/vault_reference.py b/src/kernel/types/vault_reference.py new file mode 100644 index 00000000..f22e7de8 --- /dev/null +++ b/src/kernel/types/vault_reference.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional + +from .._models import BaseModel + +__all__ = ["VaultReference"] + + +class VaultReference(BaseModel): + """Reference to a project-scoped vault. Provide exactly one of id or name.""" + + id: Optional[str] = None + + name: Optional[str] = None diff --git a/src/kernel/types/vault_reference_param.py b/src/kernel/types/vault_reference_param.py new file mode 100644 index 00000000..3e8fe9ac --- /dev/null +++ b/src/kernel/types/vault_reference_param.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["VaultReferenceParam"] + + +class VaultReferenceParam(TypedDict, total=False): + """Reference to a project-scoped vault. Provide exactly one of id or name.""" + + id: str + + name: str diff --git a/src/kernel/types/vault_upsert_params.py b/src/kernel/types/vault_upsert_params.py new file mode 100644 index 00000000..84be182b --- /dev/null +++ b/src/kernel/types/vault_upsert_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["VaultUpsertParams"] + + +class VaultUpsertParams(TypedDict, total=False): + name: Required[str] + """Immutable name used to create or retrieve the vault.""" diff --git a/src/kernel/types/vaults/__init__.py b/src/kernel/types/vaults/__init__.py new file mode 100644 index 00000000..7ee998eb --- /dev/null +++ b/src/kernel/types/vaults/__init__.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .vault_item import VaultItem as VaultItem +from .vault_item_event import VaultItemEvent as VaultItemEvent +from .vault_item_action import VaultItemAction as VaultItemAction +from .item_events_params import ItemEventsParams as ItemEventsParams +from .item_list_response import ItemListResponse as ItemListResponse +from .item_update_params import ItemUpdateParams as ItemUpdateParams +from .item_upsert_params import ItemUpsertParams as ItemUpsertParams +from .vault_card_aliases import VaultCardAliases as VaultCardAliases +from .card_vault_item_spec import CardVaultItemSpec as CardVaultItemSpec +from .item_events_response import ItemEventsResponse as ItemEventsResponse +from .item_retrieve_params import ItemRetrieveParams as ItemRetrieveParams +from .vault_payment_method import VaultPaymentMethod as VaultPaymentMethod +from .card_vault_item_state import CardVaultItemState as CardVaultItemState +from .wallet_vault_item_spec import WalletVaultItemSpec as WalletVaultItemSpec +from .wallet_vault_item_state import WalletVaultItemState as WalletVaultItemState +from .card_vault_item_spec_param import CardVaultItemSpecParam as CardVaultItemSpecParam +from .wallet_vault_item_spec_param import WalletVaultItemSpecParam as WalletVaultItemSpecParam +from .item_perform_operation_params import ItemPerformOperationParams as ItemPerformOperationParams +from .agentcard_checkout_authorization import AgentcardCheckoutAuthorization as AgentcardCheckoutAuthorization diff --git a/src/kernel/types/vaults/agentcard_checkout_authorization.py b/src/kernel/types/vaults/agentcard_checkout_authorization.py new file mode 100644 index 00000000..2a0dc815 --- /dev/null +++ b/src/kernel/types/vaults/agentcard_checkout_authorization.py @@ -0,0 +1,66 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["AgentcardCheckoutAuthorization"] + + +class AgentcardCheckoutAuthorization(BaseModel): + """The in-flight or most recent checkout authorization. + + Present while a checkout is pending approval and after it settles. + """ + + id: str + + amount_cents: int + + created_at: datetime + + currency: str + + merchant: str + + psp: str + + status: Literal["awaiting_approval", "approved", "declined", "expired"] + + actual_cents: Optional[int] = None + + amount: Optional[str] = None + """Display amount shown on the approval screen.""" + + amount_authority: Optional[Literal["display_only", "stripe_payment_intent"]] = None + + amount_verified: Optional[bool] = None + + approval_url: Optional[str] = None + + browser_id: Optional[str] = None + """Browser session that submitted the checkout.""" + + charged_amount_cents: Optional[int] = None + + charged_currency: Optional[str] = None + + charged_kind: Optional[Literal["captured", "authorized", "none"]] = None + + expected_cents: Optional[int] = None + + expires_at: Optional[datetime] = None + + psp_error_code: Optional[str] = None + + reason: Optional[str] = None + + replay_attempted: Optional[bool] = None + + replay_delivered: Optional[bool] = None + """Whether the processor response was delivered to the browser.""" + + replay_status: Optional[int] = None + """HTTP status of the replayed processor response.""" diff --git a/src/kernel/types/vaults/card_vault_item_spec.py b/src/kernel/types/vaults/card_vault_item_spec.py new file mode 100644 index 00000000..65eebebd --- /dev/null +++ b/src/kernel/types/vaults/card_vault_item_spec.py @@ -0,0 +1,125 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "CardVaultItemSpec", + "LinkCardVaultItemSpec", + "LinkCardVaultItemSpecLineItem", + "LinkCardVaultItemSpecLineItemTotal", + "LinkCardVaultItemSpecTotal", + "AgentCardCardVaultItemSpec", +] + + +class LinkCardVaultItemSpecLineItemTotal(BaseModel): + amount: int + """Total amount in minor currency units.""" + + display_text: str + + type: str + + +class LinkCardVaultItemSpecLineItem(BaseModel): + name: str + + description: Optional[str] = None + + image_url: Optional[str] = None + + product_url: Optional[str] = None + + quantity: Optional[int] = None + + sku: Optional[str] = None + + totals: Optional[List[LinkCardVaultItemSpecLineItemTotal]] = None + + unit_amount: Optional[int] = None + """Unit amount in minor currency units.""" + + url: Optional[str] = None + + +class LinkCardVaultItemSpecTotal(BaseModel): + amount: int + """Total amount in minor currency units.""" + + display_text: str + + type: str + + +class LinkCardVaultItemSpec(BaseModel): + amount: int + """Integer amount in minor currency units.""" + + context: str + + currency: str + + merchant_name: str + + merchant_url: str + + payment_method_id: str + """Payment-method ID returned by the referenced wallet's payment-method listing. + + The provider decides whether the selected funding method can satisfy the card + request. + """ + + provider: Literal["link"] + + test: bool + """ + Whether Link should return test credentials instead of a live payment + credential. + """ + + wallet: str + """Wallet item key used to mint this card.""" + + expires_at: Optional[int] = None + + line_items: Optional[List[LinkCardVaultItemSpecLineItem]] = None + + metadata: Optional[Dict[str, str]] = None + + totals: Optional[List[LinkCardVaultItemSpecTotal]] = None + + +class AgentCardCardVaultItemSpec(BaseModel): + """AgentCard reusable card. + + Each checkout creates an approval-gated authorization for spec.merchant / spec.amount. The card stays ready after each authorization. + """ + + amount: int + """Integer amount in minor currency units.""" + + currency: str + + merchant: str + """Merchant name shown on the cardholder's approval screen.""" + + provider: Literal["agentcard"] + + wallet: str + """Wallet item key used to authorize checkouts.""" + + card_id: Optional[str] = None + """AgentCard vaulted card to pay with. + + Omitted, the cardholder picks on the approval screen. + """ + + +CardVaultItemSpec: TypeAlias = Annotated[ + Union[LinkCardVaultItemSpec, AgentCardCardVaultItemSpec], PropertyInfo(discriminator="provider") +] diff --git a/src/kernel/types/vaults/card_vault_item_spec_param.py b/src/kernel/types/vaults/card_vault_item_spec_param.py new file mode 100644 index 00000000..22b81433 --- /dev/null +++ b/src/kernel/types/vaults/card_vault_item_spec_param.py @@ -0,0 +1,122 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union, Iterable +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "CardVaultItemSpecParam", + "LinkCardVaultItemSpec", + "LinkCardVaultItemSpecLineItem", + "LinkCardVaultItemSpecLineItemTotal", + "LinkCardVaultItemSpecTotal", + "AgentCardCardVaultItemSpec", +] + + +class LinkCardVaultItemSpecLineItemTotal(TypedDict, total=False): + amount: Required[int] + """Total amount in minor currency units.""" + + display_text: Required[str] + + type: Required[str] + + +class LinkCardVaultItemSpecLineItem(TypedDict, total=False): + name: Required[str] + + description: str + + image_url: str + + product_url: str + + quantity: int + + sku: str + + totals: Iterable[LinkCardVaultItemSpecLineItemTotal] + + unit_amount: int + """Unit amount in minor currency units.""" + + url: str + + +class LinkCardVaultItemSpecTotal(TypedDict, total=False): + amount: Required[int] + """Total amount in minor currency units.""" + + display_text: Required[str] + + type: Required[str] + + +class LinkCardVaultItemSpec(TypedDict, total=False): + amount: Required[int] + """Integer amount in minor currency units.""" + + context: Required[str] + + currency: Required[str] + + merchant_name: Required[str] + + merchant_url: Required[str] + + payment_method_id: Required[str] + """Payment-method ID returned by the referenced wallet's payment-method listing. + + The provider decides whether the selected funding method can satisfy the card + request. + """ + + provider: Required[Literal["link"]] + + test: Required[bool] + """ + Whether Link should return test credentials instead of a live payment + credential. + """ + + wallet: Required[str] + """Wallet item key used to mint this card.""" + + expires_at: int + + line_items: Iterable[LinkCardVaultItemSpecLineItem] + + metadata: Dict[str, str] + + totals: Iterable[LinkCardVaultItemSpecTotal] + + +class AgentCardCardVaultItemSpec(TypedDict, total=False): + """AgentCard reusable card. + + Each checkout creates an approval-gated authorization for spec.merchant / spec.amount. The card stays ready after each authorization. + """ + + amount: Required[int] + """Integer amount in minor currency units.""" + + currency: Required[str] + + merchant: Required[str] + """Merchant name shown on the cardholder's approval screen.""" + + provider: Required[Literal["agentcard"]] + + wallet: Required[str] + """Wallet item key used to authorize checkouts.""" + + card_id: str + """AgentCard vaulted card to pay with. + + Omitted, the cardholder picks on the approval screen. + """ + + +CardVaultItemSpecParam: TypeAlias = Union[LinkCardVaultItemSpec, AgentCardCardVaultItemSpec] diff --git a/src/kernel/types/vaults/card_vault_item_state.py b/src/kernel/types/vaults/card_vault_item_state.py new file mode 100644 index 00000000..4808d1ff --- /dev/null +++ b/src/kernel/types/vaults/card_vault_item_state.py @@ -0,0 +1,86 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import TYPE_CHECKING, Dict, List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from pydantic import Field as FieldInfo + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .vault_card_aliases import VaultCardAliases +from .agentcard_checkout_authorization import AgentcardCheckoutAuthorization + +__all__ = ["CardVaultItemState", "LinkCardState", "LinkCardStateMasks", "AgentCardCardState", "AgentCardCardStateMasks"] + + +class LinkCardStateMasks(BaseModel): + brand: Optional[str] = None + + last4: Optional[str] = None + + if TYPE_CHECKING: + # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a + # value to this field, so for compatibility we avoid doing it at runtime. + __pydantic_extra__: Dict[str, str] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + + # Stub to indicate that arbitrary properties are accepted. + # To access properties that are not valid identifiers you can use `getattr`, e.g. + # `getattr(obj, '$type')` + def __getattr__(self, attr: str) -> str: ... + else: + __pydantic_extra__: Dict[str, str] + + +class LinkCardState(BaseModel): + provider: Literal["link"] + + status: Literal["requested", "pending_authorization", "ready", "consumed", "expired", "declined"] + + aliases: Optional[VaultCardAliases] = None + + domains: Optional[List[str]] = None + + masks: Optional[LinkCardStateMasks] = None + + status_reason: Optional[str] = None + + +class AgentCardCardStateMasks(BaseModel): + brand: Optional[str] = None + + last4: Optional[str] = None + + if TYPE_CHECKING: + # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a + # value to this field, so for compatibility we avoid doing it at runtime. + __pydantic_extra__: Dict[str, str] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + + # Stub to indicate that arbitrary properties are accepted. + # To access properties that are not valid identifiers you can use `getattr`, e.g. + # `getattr(obj, '$type')` + def __getattr__(self, attr: str) -> str: ... + else: + __pydantic_extra__: Dict[str, str] + + +class AgentCardCardState(BaseModel): + provider: Literal["agentcard"] + + status: Literal["requested", "ready", "pending_approval", "degraded"] + + aliases: Optional[VaultCardAliases] = None + + authorization: Optional[AgentcardCheckoutAuthorization] = None + """The in-flight or most recent checkout authorization. + + Present while a checkout is pending approval and after it settles. + """ + + masks: Optional[AgentCardCardStateMasks] = None + + status_reason: Optional[str] = None + + +CardVaultItemState: TypeAlias = Annotated[ + Union[LinkCardState, AgentCardCardState], PropertyInfo(discriminator="provider") +] diff --git a/src/kernel/types/vaults/item_events_params.py b/src/kernel/types/vaults/item_events_params.py new file mode 100644 index 00000000..cee33414 --- /dev/null +++ b/src/kernel/types/vaults/item_events_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__ = ["ItemEventsParams"] + + +class ItemEventsParams(TypedDict, total=False): + id_or_name: Required[str] + + after: str + """Return events after this event ID.""" + + wait: int + """Long-poll for new events for up to this many seconds.""" diff --git a/src/kernel/types/vaults/item_events_response.py b/src/kernel/types/vaults/item_events_response.py new file mode 100644 index 00000000..fa1959fe --- /dev/null +++ b/src/kernel/types/vaults/item_events_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .vault_item_event import VaultItemEvent + +__all__ = ["ItemEventsResponse"] + +ItemEventsResponse: TypeAlias = List[VaultItemEvent] diff --git a/src/kernel/types/vaults/item_list_response.py b/src/kernel/types/vaults/item_list_response.py new file mode 100644 index 00000000..9bc1fb58 --- /dev/null +++ b/src/kernel/types/vaults/item_list_response.py @@ -0,0 +1,10 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List +from typing_extensions import TypeAlias + +from .vault_item import VaultItem + +__all__ = ["ItemListResponse"] + +ItemListResponse: TypeAlias = List[VaultItem] diff --git a/src/kernel/types/vaults/item_perform_operation_params.py b/src/kernel/types/vaults/item_perform_operation_params.py new file mode 100644 index 00000000..9d62f380 --- /dev/null +++ b/src/kernel/types/vaults/item_perform_operation_params.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ItemPerformOperationParams"] + + +class ItemPerformOperationParams(TypedDict, total=False): + id_or_name: Required[str] + + type: Required[Literal["authorize"]] diff --git a/src/kernel/types/vaults/item_retrieve_params.py b/src/kernel/types/vaults/item_retrieve_params.py new file mode 100644 index 00000000..976881b2 --- /dev/null +++ b/src/kernel/types/vaults/item_retrieve_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ItemRetrieveParams"] + + +class ItemRetrieveParams(TypedDict, total=False): + id_or_name: Required[str] + + expand: List[Literal["payment_methods"]] + """Live fields advertised by `available_expansions` to include in `expanded`.""" + + wait: int + """ + Hold for up to this many seconds while the item is pending authorization or + approval. + """ diff --git a/src/kernel/types/vaults/item_update_params.py b/src/kernel/types/vaults/item_update_params.py new file mode 100644 index 00000000..38604305 --- /dev/null +++ b/src/kernel/types/vaults/item_update_params.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +from .card_vault_item_spec_param import CardVaultItemSpecParam + +__all__ = ["ItemUpdateParams"] + + +class ItemUpdateParams(TypedDict, total=False): + id_or_name: Required[str] + + spec: Required[CardVaultItemSpecParam] + """AgentCard reusable card. + + Each checkout creates an approval-gated authorization for spec.merchant / + spec.amount. The card stays ready after each authorization. + """ diff --git a/src/kernel/types/vaults/item_upsert_params.py b/src/kernel/types/vaults/item_upsert_params.py new file mode 100644 index 00000000..5f1a4b0e --- /dev/null +++ b/src/kernel/types/vaults/item_upsert_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +from .card_vault_item_spec_param import CardVaultItemSpecParam +from .wallet_vault_item_spec_param import WalletVaultItemSpecParam + +__all__ = ["ItemUpsertParams", "WalletVaultItemRequest", "CardVaultItemRequest"] + + +class WalletVaultItemRequest(TypedDict, total=False): + id_or_name: Required[str] + + spec: Required[WalletVaultItemSpecParam] + """AgentCard wallet. + + Mode (sandbox vs live) is fixed by the deployment's AgentCard credential; there + is no per-item test flag. user_id may only reference a user already enrolled by + a wallet in this organization. + """ + + type: Required[Literal["wallet"]] + + +class CardVaultItemRequest(TypedDict, total=False): + id_or_name: Required[str] + + spec: Required[CardVaultItemSpecParam] + """AgentCard reusable card. + + Each checkout creates an approval-gated authorization for spec.merchant / + spec.amount. The card stays ready after each authorization. + """ + + type: Required[Literal["card"]] + + +ItemUpsertParams: TypeAlias = Union[WalletVaultItemRequest, CardVaultItemRequest] diff --git a/src/kernel/types/vaults/vault_card_aliases.py b/src/kernel/types/vaults/vault_card_aliases.py new file mode 100644 index 00000000..149de39f --- /dev/null +++ b/src/kernel/types/vaults/vault_card_aliases.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from ..._models import BaseModel + +__all__ = ["VaultCardAliases"] + + +class VaultCardAliases(BaseModel): + cvc: str + + exp_month: str + + exp_year: str + + number: str diff --git a/src/kernel/types/vaults/vault_item.py b/src/kernel/types/vaults/vault_item.py new file mode 100644 index 00000000..8418f0bc --- /dev/null +++ b/src/kernel/types/vaults/vault_item.py @@ -0,0 +1,140 @@ +# 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, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel +from .vault_item_action import VaultItemAction +from .card_vault_item_spec import CardVaultItemSpec +from .vault_payment_method import VaultPaymentMethod +from .card_vault_item_state import CardVaultItemState +from .wallet_vault_item_spec import WalletVaultItemSpec +from .wallet_vault_item_state import WalletVaultItemState + +__all__ = [ + "VaultItem", + "WalletVaultItem", + "WalletVaultItemAvailableExpansion", + "WalletVaultItemAvailableOperation", + "WalletVaultItemExpanded", + "CardVaultItem", + "CardVaultItemAvailableExpansion", + "CardVaultItemAvailableOperation", +] + + +class WalletVaultItemAvailableExpansion(BaseModel): + """ + Live data that can currently be requested by passing its type to the item GET expand parameter. + """ + + description: str + + type: Literal["payment_methods"] + + +class WalletVaultItemAvailableOperation(BaseModel): + """An operation that is currently valid for this item. + + Read the description before invoking it through the item operations endpoint. + """ + + description: str + + type: Literal["authorize"] + + +class WalletVaultItemExpanded(BaseModel): + """Live, non-persisted data requested through the item GET expand parameter.""" + + payment_methods: Optional[List[VaultPaymentMethod]] = None + + +class WalletVaultItem(BaseModel): + id: str + + available_expansions: List[WalletVaultItemAvailableExpansion] + + available_operations: List[WalletVaultItemAvailableOperation] + + created_at: datetime + + key: str + """Immutable item key assigned when the item is created.""" + + spec: WalletVaultItemSpec + """AgentCard wallet. + + Mode (sandbox vs live) is fixed by the deployment's AgentCard credential; there + is no per-item test flag. user_id may only reference a user already enrolled by + a wallet in this organization. + """ + + state: WalletVaultItemState + + type: Literal["wallet"] + + updated_at: datetime + + action: Optional[VaultItemAction] = None + + expanded: Optional[WalletVaultItemExpanded] = None + """Live, non-persisted data requested through the item GET expand parameter.""" + + expires_at: Optional[datetime] = None + + +class CardVaultItemAvailableExpansion(BaseModel): + """ + Live data that can currently be requested by passing its type to the item GET expand parameter. + """ + + description: str + + type: Literal["payment_methods"] + + +class CardVaultItemAvailableOperation(BaseModel): + """An operation that is currently valid for this item. + + Read the description before invoking it through the item operations endpoint. + """ + + description: str + + type: Literal["authorize"] + + +class CardVaultItem(BaseModel): + id: str + + available_expansions: List[CardVaultItemAvailableExpansion] + + available_operations: List[CardVaultItemAvailableOperation] + + created_at: datetime + + key: str + """Immutable item key assigned when the item is created.""" + + spec: CardVaultItemSpec + """AgentCard reusable card. + + Each checkout creates an approval-gated authorization for spec.merchant / + spec.amount. The card stays ready after each authorization. + """ + + state: CardVaultItemState + + type: Literal["card"] + + updated_at: datetime + + action: Optional[VaultItemAction] = None + + expires_at: Optional[datetime] = None + + +VaultItem: TypeAlias = Annotated[Union[WalletVaultItem, CardVaultItem], PropertyInfo(discriminator="type")] diff --git a/src/kernel/types/vaults/vault_item_action.py b/src/kernel/types/vaults/vault_item_action.py new file mode 100644 index 00000000..9054447e --- /dev/null +++ b/src/kernel/types/vaults/vault_item_action.py @@ -0,0 +1,66 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "VaultItemAction", + "LinkOAuthAction", + "SpendApprovalAction", + "PushApprovalAction", + "CollectAction", + "MfaAction", + "EmbeddedCeremonyAction", + "CardEnrollmentAction", +] + + +class LinkOAuthAction(BaseModel): + name: Literal["link_oauth"] + + url: str + + +class SpendApprovalAction(BaseModel): + name: Literal["spend_approval"] + + url: str + + +class PushApprovalAction(BaseModel): + name: Literal["push_approval"] + + +class CollectAction(BaseModel): + name: Literal["collect"] + + +class MfaAction(BaseModel): + name: Literal["mfa"] + + +class EmbeddedCeremonyAction(BaseModel): + name: Literal["embedded_ceremony"] + + +class CardEnrollmentAction(BaseModel): + name: Literal["card_enrollment"] + + url: str + + +VaultItemAction: TypeAlias = Annotated[ + Union[ + LinkOAuthAction, + SpendApprovalAction, + PushApprovalAction, + CollectAction, + MfaAction, + EmbeddedCeremonyAction, + CardEnrollmentAction, + ], + PropertyInfo(discriminator="name"), +] diff --git a/src/kernel/types/vaults/vault_item_event.py b/src/kernel/types/vaults/vault_item_event.py new file mode 100644 index 00000000..2d4098be --- /dev/null +++ b/src/kernel/types/vaults/vault_item_event.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Dict, Optional +from datetime import datetime + +from ..._models import BaseModel + +__all__ = ["VaultItemEvent"] + + +class VaultItemEvent(BaseModel): + id: str + + created_at: datetime + + name: str + + browser_id: Optional[str] = None + """Browser session associated with the event, when applicable.""" + + data: Optional[Dict[str, object]] = None diff --git a/src/kernel/types/vaults/vault_payment_method.py b/src/kernel/types/vaults/vault_payment_method.py new file mode 100644 index 00000000..27f87ad1 --- /dev/null +++ b/src/kernel/types/vaults/vault_payment_method.py @@ -0,0 +1,51 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional + +from ..._models import BaseModel + +__all__ = ["VaultPaymentMethod", "Capabilities", "CapabilitiesSingleUseCard", "Display"] + + +class CapabilitiesSingleUseCard(BaseModel): + eligible: bool + + reasons: List[str] + + +class Capabilities(BaseModel): + """Provider-reported advisory capabilities. + + A missing capability is unknown, not ineligible; only eligible=false is an explicit negative signal. + """ + + single_use_card: Optional[CapabilitiesSingleUseCard] = None + + +class Display(BaseModel): + brand: Optional[str] = None + + label: Optional[str] = None + + last4: Optional[str] = None + + +class VaultPaymentMethod(BaseModel): + id: str + + capabilities: Capabilities + """Provider-reported advisory capabilities. + + A missing capability is unknown, not ineligible; only eligible=false is an + explicit negative signal. + """ + + display: Display + + is_default: bool + + provider: str + """Provider that issued this payment-method ID.""" + + type: str + """Provider-neutral payment-method type normalized to lowercase.""" diff --git a/src/kernel/types/vaults/wallet_vault_item_spec.py b/src/kernel/types/vaults/wallet_vault_item_spec.py new file mode 100644 index 00000000..03176670 --- /dev/null +++ b/src/kernel/types/vaults/wallet_vault_item_spec.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = [ + "WalletVaultItemSpec", + "LinkWalletVaultItemSpec", + "LinkWalletVaultItemSpecAuthorization", + "LinkWalletVaultItemSpecAuthorizationClient", + "AgentCardWalletVaultItemSpec", +] + + +class LinkWalletVaultItemSpecAuthorizationClient(BaseModel): + type: Literal["kernel_managed"] + + +class LinkWalletVaultItemSpecAuthorization(BaseModel): + client: LinkWalletVaultItemSpecAuthorizationClient + + method: Literal["oauth"] + + +class LinkWalletVaultItemSpec(BaseModel): + authorization: LinkWalletVaultItemSpecAuthorization + + provider: Literal["link"] + + +class AgentCardWalletVaultItemSpec(BaseModel): + """AgentCard wallet. + + Mode (sandbox vs live) is fixed by the deployment's AgentCard credential; there is no per-item test flag. user_id may only reference a user already enrolled by a wallet in this organization. + """ + + provider: Literal["agentcard"] + + user_id: Optional[str] = None + + +WalletVaultItemSpec: TypeAlias = Annotated[ + Union[LinkWalletVaultItemSpec, AgentCardWalletVaultItemSpec], PropertyInfo(discriminator="provider") +] diff --git a/src/kernel/types/vaults/wallet_vault_item_spec_param.py b/src/kernel/types/vaults/wallet_vault_item_spec_param.py new file mode 100644 index 00000000..dc30e054 --- /dev/null +++ b/src/kernel/types/vaults/wallet_vault_item_spec_param.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Literal, Required, TypeAlias, TypedDict + +__all__ = [ + "WalletVaultItemSpecParam", + "LinkWalletVaultItemSpec", + "LinkWalletVaultItemSpecAuthorization", + "LinkWalletVaultItemSpecAuthorizationClient", + "AgentCardWalletVaultItemSpec", +] + + +class LinkWalletVaultItemSpecAuthorizationClient(TypedDict, total=False): + type: Required[Literal["kernel_managed"]] + + +class LinkWalletVaultItemSpecAuthorization(TypedDict, total=False): + client: Required[LinkWalletVaultItemSpecAuthorizationClient] + + method: Required[Literal["oauth"]] + + +class LinkWalletVaultItemSpec(TypedDict, total=False): + authorization: Required[LinkWalletVaultItemSpecAuthorization] + + provider: Required[Literal["link"]] + + +class AgentCardWalletVaultItemSpec(TypedDict, total=False): + """AgentCard wallet. + + Mode (sandbox vs live) is fixed by the deployment's AgentCard credential; there is no per-item test flag. user_id may only reference a user already enrolled by a wallet in this organization. + """ + + provider: Required[Literal["agentcard"]] + + user_id: str + + +WalletVaultItemSpecParam: TypeAlias = Union[LinkWalletVaultItemSpec, AgentCardWalletVaultItemSpec] diff --git a/src/kernel/types/vaults/wallet_vault_item_state.py b/src/kernel/types/vaults/wallet_vault_item_state.py new file mode 100644 index 00000000..9b76f419 --- /dev/null +++ b/src/kernel/types/vaults/wallet_vault_item_state.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias + +from ..._utils import PropertyInfo +from ..._models import BaseModel + +__all__ = ["WalletVaultItemState", "LinkWalletState", "AgentCardWalletState"] + + +class LinkWalletState(BaseModel): + provider: Literal["link"] + + status: Literal["pending_authorization", "connected", "declined", "reconnect_required", "degraded"] + + status_reason: Optional[str] = None + + +class AgentCardWalletState(BaseModel): + provider: Literal["agentcard"] + + status: Literal["pending_authorization", "connected", "degraded"] + + status_reason: Optional[str] = None + + user_id: Optional[str] = None + """AgentCard user id linked to this wallet. Present once connected.""" + + +WalletVaultItemState: TypeAlias = Annotated[ + Union[LinkWalletState, AgentCardWalletState], PropertyInfo(discriminator="provider") +] diff --git a/tests/api_resources/test_browsers.py b/tests/api_resources/test_browsers.py index 3d0a3eb6..406b0ce8 100644 --- a/tests/api_resources/test_browsers.py +++ b/tests/api_resources/test_browsers.py @@ -94,6 +94,12 @@ def test_method_create_with_all_params(self, client: Kernel) -> None: }, }, timeout_seconds=10, + vaults=[ + { + "id": "id", + "name": "x", + } + ], viewport={ "height": 800, "width": 1280, @@ -561,6 +567,12 @@ async def test_method_create_with_all_params(self, async_client: AsyncKernel) -> }, }, timeout_seconds=10, + vaults=[ + { + "id": "id", + "name": "x", + } + ], viewport={ "height": 800, "width": 1280, diff --git a/tests/api_resources/test_vaults.py b/tests/api_resources/test_vaults.py new file mode 100644 index 00000000..0836a7f8 --- /dev/null +++ b/tests/api_resources/test_vaults.py @@ -0,0 +1,335 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from kernel import Kernel, AsyncKernel +from tests.utils import assert_matches_type +from kernel.types import Vault +from kernel.pagination import SyncOffsetPagination, AsyncOffsetPagination + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestVaults: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Kernel) -> None: + vault = client.vaults.retrieve( + "id_or_name", + ) + assert_matches_type(Vault, vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Kernel) -> None: + response = client.vaults.with_raw_response.retrieve( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = response.parse() + assert_matches_type(Vault, vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Kernel) -> None: + with client.vaults.with_streaming_response.retrieve( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = response.parse() + assert_matches_type(Vault, vault, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.vaults.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Kernel) -> None: + vault = client.vaults.list() + assert_matches_type(SyncOffsetPagination[Vault], vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Kernel) -> None: + vault = client.vaults.list( + limit=1, + offset=0, + ) + assert_matches_type(SyncOffsetPagination[Vault], vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Kernel) -> None: + response = client.vaults.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = response.parse() + assert_matches_type(SyncOffsetPagination[Vault], vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Kernel) -> None: + with client.vaults.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = response.parse() + assert_matches_type(SyncOffsetPagination[Vault], vault, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Kernel) -> None: + vault = client.vaults.delete( + "id_or_name", + ) + assert vault is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Kernel) -> None: + response = client.vaults.with_raw_response.delete( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = response.parse() + assert vault is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Kernel) -> None: + with client.vaults.with_streaming_response.delete( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = response.parse() + assert vault is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_delete(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.vaults.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_upsert(self, client: Kernel) -> None: + vault = client.vaults.upsert( + name="name", + ) + assert_matches_type(Vault, vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_upsert(self, client: Kernel) -> None: + response = client.vaults.with_raw_response.upsert( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = response.parse() + assert_matches_type(Vault, vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_upsert(self, client: Kernel) -> None: + with client.vaults.with_streaming_response.upsert( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = response.parse() + assert_matches_type(Vault, vault, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncVaults: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncKernel) -> None: + vault = await async_client.vaults.retrieve( + "id_or_name", + ) + assert_matches_type(Vault, vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.with_raw_response.retrieve( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = await response.parse() + assert_matches_type(Vault, vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.with_streaming_response.retrieve( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = await response.parse() + assert_matches_type(Vault, vault, 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_retrieve(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.vaults.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncKernel) -> None: + vault = await async_client.vaults.list() + assert_matches_type(AsyncOffsetPagination[Vault], vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncKernel) -> None: + vault = await async_client.vaults.list( + limit=1, + offset=0, + ) + assert_matches_type(AsyncOffsetPagination[Vault], vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = await response.parse() + assert_matches_type(AsyncOffsetPagination[Vault], vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = await response.parse() + assert_matches_type(AsyncOffsetPagination[Vault], vault, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncKernel) -> None: + vault = await async_client.vaults.delete( + "id_or_name", + ) + assert vault is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.with_raw_response.delete( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = await response.parse() + assert vault is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.with_streaming_response.delete( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = await response.parse() + assert vault is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_delete(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.vaults.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_upsert(self, async_client: AsyncKernel) -> None: + vault = await async_client.vaults.upsert( + name="name", + ) + assert_matches_type(Vault, vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_upsert(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.with_raw_response.upsert( + name="name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + vault = await response.parse() + assert_matches_type(Vault, vault, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_upsert(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.with_streaming_response.upsert( + name="name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + vault = await response.parse() + assert_matches_type(Vault, vault, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/vaults/__init__.py b/tests/api_resources/vaults/__init__.py new file mode 100644 index 00000000..fd8019a9 --- /dev/null +++ b/tests/api_resources/vaults/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/vaults/test_items.py b/tests/api_resources/vaults/test_items.py new file mode 100644 index 00000000..9d0f9ec6 --- /dev/null +++ b/tests/api_resources/vaults/test_items.py @@ -0,0 +1,1432 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from kernel import Kernel, AsyncKernel +from tests.utils import assert_matches_type +from kernel.types.vaults import ( + VaultItem, + ItemListResponse, + ItemEventsResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestItems: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Kernel) -> None: + item = client.vaults.items.retrieve( + key="x", + id_or_name="id_or_name", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve_with_all_params(self, client: Kernel) -> None: + item = client.vaults.items.retrieve( + key="x", + id_or_name="id_or_name", + expand=["payment_methods"], + wait=0, + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Kernel) -> None: + response = client.vaults.items.with_raw_response.retrieve( + key="x", + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Kernel) -> None: + with client.vaults.items.with_streaming_response.retrieve( + key="x", + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.vaults.items.with_raw_response.retrieve( + key="x", + id_or_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + client.vaults.items.with_raw_response.retrieve( + key="", + id_or_name="id_or_name", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update(self, client: Kernel) -> None: + item = client.vaults.items.update( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update_with_all_params(self, client: Kernel) -> None: + item = client.vaults.items.update( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + "expires_at": 0, + "line_items": [ + { + "name": "name", + "description": "description", + "image_url": "image_url", + "product_url": "product_url", + "quantity": 1, + "sku": "sku", + "totals": [ + { + "amount": 0, + "display_text": "display_text", + "type": "type", + } + ], + "unit_amount": 0, + "url": "url", + } + ], + "metadata": {"foo": "string"}, + "totals": [ + { + "amount": 0, + "display_text": "display_text", + "type": "type", + } + ], + }, + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_update(self, client: Kernel) -> None: + response = client.vaults.items.with_raw_response.update( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_update(self, client: Kernel) -> None: + with client.vaults.items.with_streaming_response.update( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(VaultItem, item, 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.vaults.items.with_raw_response.update( + key="x", + id_or_name="", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + client.vaults.items.with_raw_response.update( + key="", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Kernel) -> None: + item = client.vaults.items.list( + "id_or_name", + ) + assert_matches_type(ItemListResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Kernel) -> None: + response = client.vaults.items.with_raw_response.list( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(ItemListResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Kernel) -> None: + with client.vaults.items.with_streaming_response.list( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(ItemListResponse, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_list(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.vaults.items.with_raw_response.list( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Kernel) -> None: + item = client.vaults.items.delete( + key="x", + id_or_name="id_or_name", + ) + assert item is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Kernel) -> None: + response = client.vaults.items.with_raw_response.delete( + key="x", + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert item is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Kernel) -> None: + with client.vaults.items.with_streaming_response.delete( + key="x", + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert item is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_delete(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.vaults.items.with_raw_response.delete( + key="x", + id_or_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + client.vaults.items.with_raw_response.delete( + key="", + id_or_name="id_or_name", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_events(self, client: Kernel) -> None: + item = client.vaults.items.events( + key="key", + id_or_name="id_or_name", + ) + assert_matches_type(ItemEventsResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_events_with_all_params(self, client: Kernel) -> None: + item = client.vaults.items.events( + key="key", + id_or_name="id_or_name", + after="after", + wait=0, + ) + assert_matches_type(ItemEventsResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_events(self, client: Kernel) -> None: + response = client.vaults.items.with_raw_response.events( + key="key", + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(ItemEventsResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_events(self, client: Kernel) -> None: + with client.vaults.items.with_streaming_response.events( + key="key", + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(ItemEventsResponse, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_events(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.vaults.items.with_raw_response.events( + key="key", + id_or_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + client.vaults.items.with_raw_response.events( + key="", + id_or_name="id_or_name", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_perform_operation(self, client: Kernel) -> None: + item = client.vaults.items.perform_operation( + key="key", + id_or_name="id_or_name", + type="authorize", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_perform_operation(self, client: Kernel) -> None: + response = client.vaults.items.with_raw_response.perform_operation( + key="key", + id_or_name="id_or_name", + type="authorize", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_perform_operation(self, client: Kernel) -> None: + with client.vaults.items.with_streaming_response.perform_operation( + key="key", + id_or_name="id_or_name", + type="authorize", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_perform_operation(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.vaults.items.with_raw_response.perform_operation( + key="key", + id_or_name="", + type="authorize", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + client.vaults.items.with_raw_response.perform_operation( + key="", + id_or_name="id_or_name", + type="authorize", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_upsert_overload_1(self, client: Kernel) -> None: + item = client.vaults.items.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_upsert_with_all_params_overload_1(self, client: Kernel) -> None: + item = client.vaults.items.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_upsert_overload_1(self, client: Kernel) -> None: + response = client.vaults.items.with_raw_response.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_upsert_overload_1(self, client: Kernel) -> None: + with client.vaults.items.with_streaming_response.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_upsert_overload_1(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.vaults.items.with_raw_response.upsert( + key="x", + id_or_name="", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + client.vaults.items.with_raw_response.upsert( + key="", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_upsert_overload_2(self, client: Kernel) -> None: + item = client.vaults.items.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_upsert_with_all_params_overload_2(self, client: Kernel) -> None: + item = client.vaults.items.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + "expires_at": 0, + "line_items": [ + { + "name": "name", + "description": "description", + "image_url": "image_url", + "product_url": "product_url", + "quantity": 1, + "sku": "sku", + "totals": [ + { + "amount": 0, + "display_text": "display_text", + "type": "type", + } + ], + "unit_amount": 0, + "url": "url", + } + ], + "metadata": {"foo": "string"}, + "totals": [ + { + "amount": 0, + "display_text": "display_text", + "type": "type", + } + ], + }, + type="card", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_upsert_overload_2(self, client: Kernel) -> None: + response = client.vaults.items.with_raw_response.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_upsert_overload_2(self, client: Kernel) -> None: + with client.vaults.items.with_streaming_response.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_upsert_overload_2(self, client: Kernel) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id_or_name` but received ''"): + client.vaults.items.with_raw_response.upsert( + key="x", + id_or_name="", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + client.vaults.items.with_raw_response.upsert( + key="", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + ) + + +class TestAsyncItems: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.retrieve( + key="x", + id_or_name="id_or_name", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve_with_all_params(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.retrieve( + key="x", + id_or_name="id_or_name", + expand=["payment_methods"], + wait=0, + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.items.with_raw_response.retrieve( + key="x", + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = await response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.items.with_streaming_response.retrieve( + key="x", + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(VaultItem, item, 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_retrieve(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.vaults.items.with_raw_response.retrieve( + key="x", + id_or_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + await async_client.vaults.items.with_raw_response.retrieve( + key="", + id_or_name="id_or_name", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.update( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.update( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + "expires_at": 0, + "line_items": [ + { + "name": "name", + "description": "description", + "image_url": "image_url", + "product_url": "product_url", + "quantity": 1, + "sku": "sku", + "totals": [ + { + "amount": 0, + "display_text": "display_text", + "type": "type", + } + ], + "unit_amount": 0, + "url": "url", + } + ], + "metadata": {"foo": "string"}, + "totals": [ + { + "amount": 0, + "display_text": "display_text", + "type": "type", + } + ], + }, + ) + assert_matches_type(VaultItem, item, 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.vaults.items.with_raw_response.update( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = await response.parse() + assert_matches_type(VaultItem, item, 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.vaults.items.with_streaming_response.update( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(VaultItem, item, 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.vaults.items.with_raw_response.update( + key="x", + id_or_name="", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + await async_client.vaults.items.with_raw_response.update( + key="", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.list( + "id_or_name", + ) + assert_matches_type(ItemListResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.items.with_raw_response.list( + "id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = await response.parse() + assert_matches_type(ItemListResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.items.with_streaming_response.list( + "id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(ItemListResponse, item, 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_list(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.vaults.items.with_raw_response.list( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.delete( + key="x", + id_or_name="id_or_name", + ) + assert item is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.items.with_raw_response.delete( + key="x", + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = await response.parse() + assert item is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.items.with_streaming_response.delete( + key="x", + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert item is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_delete(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.vaults.items.with_raw_response.delete( + key="x", + id_or_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + await async_client.vaults.items.with_raw_response.delete( + key="", + id_or_name="id_or_name", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_events(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.events( + key="key", + id_or_name="id_or_name", + ) + assert_matches_type(ItemEventsResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_events_with_all_params(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.events( + key="key", + id_or_name="id_or_name", + after="after", + wait=0, + ) + assert_matches_type(ItemEventsResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_events(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.items.with_raw_response.events( + key="key", + id_or_name="id_or_name", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = await response.parse() + assert_matches_type(ItemEventsResponse, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_events(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.items.with_streaming_response.events( + key="key", + id_or_name="id_or_name", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(ItemEventsResponse, item, 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_events(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.vaults.items.with_raw_response.events( + key="key", + id_or_name="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + await async_client.vaults.items.with_raw_response.events( + key="", + id_or_name="id_or_name", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_perform_operation(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.perform_operation( + key="key", + id_or_name="id_or_name", + type="authorize", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_perform_operation(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.items.with_raw_response.perform_operation( + key="key", + id_or_name="id_or_name", + type="authorize", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = await response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_perform_operation(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.items.with_streaming_response.perform_operation( + key="key", + id_or_name="id_or_name", + type="authorize", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(VaultItem, item, 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_perform_operation(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.vaults.items.with_raw_response.perform_operation( + key="key", + id_or_name="", + type="authorize", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + await async_client.vaults.items.with_raw_response.perform_operation( + key="", + id_or_name="id_or_name", + type="authorize", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_upsert_overload_1(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_upsert_with_all_params_overload_1(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_upsert_overload_1(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.items.with_raw_response.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = await response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_upsert_overload_1(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.items.with_streaming_response.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(VaultItem, item, 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_upsert_overload_1(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.vaults.items.with_raw_response.upsert( + key="x", + id_or_name="", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + await async_client.vaults.items.with_raw_response.upsert( + key="", + id_or_name="id_or_name", + spec={ + "authorization": { + "client": {"type": "kernel_managed"}, + "method": "oauth", + }, + "provider": "link", + }, + type="wallet", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_upsert_overload_2(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_upsert_with_all_params_overload_2(self, async_client: AsyncKernel) -> None: + item = await async_client.vaults.items.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + "expires_at": 0, + "line_items": [ + { + "name": "name", + "description": "description", + "image_url": "image_url", + "product_url": "product_url", + "quantity": 1, + "sku": "sku", + "totals": [ + { + "amount": 0, + "display_text": "display_text", + "type": "type", + } + ], + "unit_amount": 0, + "url": "url", + } + ], + "metadata": {"foo": "string"}, + "totals": [ + { + "amount": 0, + "display_text": "display_text", + "type": "type", + } + ], + }, + type="card", + ) + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_upsert_overload_2(self, async_client: AsyncKernel) -> None: + response = await async_client.vaults.items.with_raw_response.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + item = await response.parse() + assert_matches_type(VaultItem, item, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_upsert_overload_2(self, async_client: AsyncKernel) -> None: + async with async_client.vaults.items.with_streaming_response.upsert( + key="x", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + item = await response.parse() + assert_matches_type(VaultItem, item, 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_upsert_overload_2(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.vaults.items.with_raw_response.upsert( + key="x", + id_or_name="", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `key` but received ''"): + await async_client.vaults.items.with_raw_response.upsert( + key="", + id_or_name="id_or_name", + spec={ + "amount": 1, + "context": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "currency": "bFx", + "merchant_name": "x", + "merchant_url": "https://example.com", + "payment_method_id": "x", + "provider": "link", + "test": True, + "wallet": "wallet", + }, + type="card", + )