diff --git a/robosystems_client/api/auth/get_passkey_registration_options.py b/robosystems_client/api/auth/get_passkey_registration_options.py index 2bc5393..af5603c 100644 --- a/robosystems_client/api/auth/get_passkey_registration_options.py +++ b/robosystems_client/api/auth/get_passkey_registration_options.py @@ -83,17 +83,22 @@ def _build_response( def sync_detailed( *, - client: AuthenticatedClient, + client: AuthenticatedClient | Client, body: PasskeyRegisterOptionsRequest, ) -> Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError]: """Passkey Registration Options - Begin a passkey enrollment ceremony. + Begin a passkey enrollment ceremony. The settings lane requires a fresh re-auth proof (password or + assertion); the forced lane presents its enrollment token. Args: - body (PasskeyRegisterOptionsRequest): Begin enrollment. mfa_token is the forced-enrollment - lane; omitted for - an authenticated settings-flow enrollment. + body (PasskeyRegisterOptionsRequest): Begin enrollment. + + Two disjoint lanes: ``mfa_token`` (forced enrollment — the token was minted + seconds after a password verify, so it is its own freshness proof) or an + authenticated settings-flow enrollment, which must carry a fresh re-auth + proof — ``password``, or a ``reauth``-ceremony ``assertion`` when adding a + passkey beside an existing one. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -116,17 +121,22 @@ def sync_detailed( def sync( *, - client: AuthenticatedClient, + client: AuthenticatedClient | Client, body: PasskeyRegisterOptionsRequest, ) -> CeremonyOptionsResponse | ErrorResponse | HTTPValidationError | None: """Passkey Registration Options - Begin a passkey enrollment ceremony. + Begin a passkey enrollment ceremony. The settings lane requires a fresh re-auth proof (password or + assertion); the forced lane presents its enrollment token. Args: - body (PasskeyRegisterOptionsRequest): Begin enrollment. mfa_token is the forced-enrollment - lane; omitted for - an authenticated settings-flow enrollment. + body (PasskeyRegisterOptionsRequest): Begin enrollment. + + Two disjoint lanes: ``mfa_token`` (forced enrollment — the token was minted + seconds after a password verify, so it is its own freshness proof) or an + authenticated settings-flow enrollment, which must carry a fresh re-auth + proof — ``password``, or a ``reauth``-ceremony ``assertion`` when adding a + passkey beside an existing one. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -144,17 +154,22 @@ def sync( async def asyncio_detailed( *, - client: AuthenticatedClient, + client: AuthenticatedClient | Client, body: PasskeyRegisterOptionsRequest, ) -> Response[CeremonyOptionsResponse | ErrorResponse | HTTPValidationError]: """Passkey Registration Options - Begin a passkey enrollment ceremony. + Begin a passkey enrollment ceremony. The settings lane requires a fresh re-auth proof (password or + assertion); the forced lane presents its enrollment token. Args: - body (PasskeyRegisterOptionsRequest): Begin enrollment. mfa_token is the forced-enrollment - lane; omitted for - an authenticated settings-flow enrollment. + body (PasskeyRegisterOptionsRequest): Begin enrollment. + + Two disjoint lanes: ``mfa_token`` (forced enrollment — the token was minted + seconds after a password verify, so it is its own freshness proof) or an + authenticated settings-flow enrollment, which must carry a fresh re-auth + proof — ``password``, or a ``reauth``-ceremony ``assertion`` when adding a + passkey beside an existing one. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -175,17 +190,22 @@ async def asyncio_detailed( async def asyncio( *, - client: AuthenticatedClient, + client: AuthenticatedClient | Client, body: PasskeyRegisterOptionsRequest, ) -> CeremonyOptionsResponse | ErrorResponse | HTTPValidationError | None: """Passkey Registration Options - Begin a passkey enrollment ceremony. + Begin a passkey enrollment ceremony. The settings lane requires a fresh re-auth proof (password or + assertion); the forced lane presents its enrollment token. Args: - body (PasskeyRegisterOptionsRequest): Begin enrollment. mfa_token is the forced-enrollment - lane; omitted for - an authenticated settings-flow enrollment. + body (PasskeyRegisterOptionsRequest): Begin enrollment. + + Two disjoint lanes: ``mfa_token`` (forced enrollment — the token was minted + seconds after a password verify, so it is its own freshness proof) or an + authenticated settings-flow enrollment, which must carry a fresh re-auth + proof — ``password``, or a ``reauth``-ceremony ``assertion`` when adding a + passkey beside an existing one. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/robosystems_client/api/auth/verify_passkey_registration.py b/robosystems_client/api/auth/verify_passkey_registration.py index 0c654d7..bc9be0c 100644 --- a/robosystems_client/api/auth/verify_passkey_registration.py +++ b/robosystems_client/api/auth/verify_passkey_registration.py @@ -83,7 +83,7 @@ def _build_response( def sync_detailed( *, - client: AuthenticatedClient, + client: AuthenticatedClient | Client, body: PasskeyRegisterVerifyRequest, ) -> Response[ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse]: """Passkey Registration Verify @@ -116,7 +116,7 @@ def sync_detailed( def sync( *, - client: AuthenticatedClient, + client: AuthenticatedClient | Client, body: PasskeyRegisterVerifyRequest, ) -> ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse | None: """Passkey Registration Verify @@ -144,7 +144,7 @@ def sync( async def asyncio_detailed( *, - client: AuthenticatedClient, + client: AuthenticatedClient | Client, body: PasskeyRegisterVerifyRequest, ) -> Response[ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse]: """Passkey Registration Verify @@ -175,7 +175,7 @@ async def asyncio_detailed( async def asyncio( *, - client: AuthenticatedClient, + client: AuthenticatedClient | Client, body: PasskeyRegisterVerifyRequest, ) -> ErrorResponse | HTTPValidationError | PasskeyRegisterVerifyResponse | None: """Passkey Registration Verify diff --git a/robosystems_client/api/billing/get_checkout_status.py b/robosystems_client/api/billing/get_checkout_status.py index 1cc8694..159b08e 100644 --- a/robosystems_client/api/billing/get_checkout_status.py +++ b/robosystems_client/api/billing/get_checkout_status.py @@ -94,8 +94,8 @@ def sync_detailed( """Get Checkout Session Status Poll after returning from Stripe Checkout. Status progresses: pending_payment → provisioning → - active. When active, resource_id is populated; for graphs, operation_id tracks SSE provisioning - progress. + active. When active, resource_id is populated. `operation_id` is always null for webhook-driven + provisioning and cannot be used to follow progress — poll this endpoint instead. Args: session_id (str): @@ -127,8 +127,8 @@ def sync( """Get Checkout Session Status Poll after returning from Stripe Checkout. Status progresses: pending_payment → provisioning → - active. When active, resource_id is populated; for graphs, operation_id tracks SSE provisioning - progress. + active. When active, resource_id is populated. `operation_id` is always null for webhook-driven + provisioning and cannot be used to follow progress — poll this endpoint instead. Args: session_id (str): @@ -155,8 +155,8 @@ async def asyncio_detailed( """Get Checkout Session Status Poll after returning from Stripe Checkout. Status progresses: pending_payment → provisioning → - active. When active, resource_id is populated; for graphs, operation_id tracks SSE provisioning - progress. + active. When active, resource_id is populated. `operation_id` is always null for webhook-driven + provisioning and cannot be used to follow progress — poll this endpoint instead. Args: session_id (str): @@ -186,8 +186,8 @@ async def asyncio( """Get Checkout Session Status Poll after returning from Stripe Checkout. Status progresses: pending_payment → provisioning → - active. When active, resource_id is populated; for graphs, operation_id tracks SSE provisioning - progress. + active. When active, resource_id is populated. `operation_id` is always null for webhook-driven + provisioning and cannot be used to follow progress — poll this endpoint instead. Args: session_id (str): diff --git a/robosystems_client/models/__init__.py b/robosystems_client/models/__init__.py index 77c790c..c8bd0b4 100644 --- a/robosystems_client/models/__init__.py +++ b/robosystems_client/models/__init__.py @@ -639,6 +639,9 @@ from .passkey_login_verify_request import PasskeyLoginVerifyRequest from .passkey_login_verify_request_assertion import PasskeyLoginVerifyRequestAssertion from .passkey_register_options_request import PasskeyRegisterOptionsRequest +from .passkey_register_options_request_assertion_type_0 import ( + PasskeyRegisterOptionsRequestAssertionType0, +) from .passkey_register_verify_request import PasskeyRegisterVerifyRequest from .passkey_register_verify_request_credential import ( PasskeyRegisterVerifyRequestCredential, @@ -1330,6 +1333,7 @@ "PasskeyLoginVerifyRequest", "PasskeyLoginVerifyRequestAssertion", "PasskeyRegisterOptionsRequest", + "PasskeyRegisterOptionsRequestAssertionType0", "PasskeyRegisterVerifyRequest", "PasskeyRegisterVerifyRequestCredential", "PasskeyRegisterVerifyResponse", diff --git a/robosystems_client/models/checkout_status_response.py b/robosystems_client/models/checkout_status_response.py index 91e81e1..98e910e 100644 --- a/robosystems_client/models/checkout_status_response.py +++ b/robosystems_client/models/checkout_status_response.py @@ -20,7 +20,10 @@ class CheckoutStatusResponse: subscription_id (str): Internal subscription ID resource_id (None | str | Unset): Resource ID (graph_id for both graphs and repositories) once provisioned. For repositories, this is the repository slug (e.g., 'sec') - operation_id (None | str | Unset): SSE operation ID for monitoring provisioning progress + operation_id (None | str | Unset): Always null. Webhook-driven provisioning passes no operation id + (`_trigger_resource_provisioning` calls `run_graph_provisioning` with `operation_id=None`), so there is no SSE + stream to follow — poll the status endpoint instead. Retained rather than removed because it is on a published + response shape; wiring it is a feature, not a fix. error (None | str | Unset): Error message if checkout failed """ diff --git a/robosystems_client/models/file_upload_request.py b/robosystems_client/models/file_upload_request.py index afe4737..b2f0a52 100644 --- a/robosystems_client/models/file_upload_request.py +++ b/robosystems_client/models/file_upload_request.py @@ -17,11 +17,15 @@ class FileUploadRequest: file_name (str): File name to upload content_type (str | Unset): File MIME type Default: 'application/x-parquet'. table_name (None | str | Unset): Table name to associate file with (required for first-class /files endpoint) + file_size_bytes (int | None | Unset): Size of the file about to be uploaded, in bytes. Optional; when supplied, + an over-limit file is rejected here instead of after it has been pushed to S3 and rejected by ingest-file. + Advisory only — the authoritative check measures the object after upload. """ file_name: str content_type: str | Unset = "application/x-parquet" table_name: None | str | Unset = UNSET + file_size_bytes: int | None | Unset = UNSET def to_dict(self) -> dict[str, Any]: file_name = self.file_name @@ -34,6 +38,12 @@ def to_dict(self) -> dict[str, Any]: else: table_name = self.table_name + file_size_bytes: int | None | Unset + if isinstance(self.file_size_bytes, Unset): + file_size_bytes = UNSET + else: + file_size_bytes = self.file_size_bytes + field_dict: dict[str, Any] = {} field_dict.update( @@ -45,6 +55,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["content_type"] = content_type if table_name is not UNSET: field_dict["table_name"] = table_name + if file_size_bytes is not UNSET: + field_dict["file_size_bytes"] = file_size_bytes return field_dict @@ -64,10 +76,20 @@ def _parse_table_name(data: object) -> None | str | Unset: table_name = _parse_table_name(d.pop("table_name", UNSET)) + def _parse_file_size_bytes(data: object) -> int | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(int | None | Unset, data) + + file_size_bytes = _parse_file_size_bytes(d.pop("file_size_bytes", UNSET)) + file_upload_request = cls( file_name=file_name, content_type=content_type, table_name=table_name, + file_size_bytes=file_size_bytes, ) return file_upload_request diff --git a/robosystems_client/models/passkey_register_options_request.py b/robosystems_client/models/passkey_register_options_request.py index d43142a..a5d15a1 100644 --- a/robosystems_client/models/passkey_register_options_request.py +++ b/robosystems_client/models/passkey_register_options_request.py @@ -1,45 +1,87 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, TypeVar, cast +from typing import TYPE_CHECKING, Any, TypeVar, cast from attrs import define as _attrs_define from attrs import field as _attrs_field from ..types import UNSET, Unset +if TYPE_CHECKING: + from ..models.passkey_register_options_request_assertion_type_0 import ( + PasskeyRegisterOptionsRequestAssertionType0, + ) + + T = TypeVar("T", bound="PasskeyRegisterOptionsRequest") @_attrs_define class PasskeyRegisterOptionsRequest: - """Begin enrollment. mfa_token is the forced-enrollment lane; omitted for - an authenticated settings-flow enrollment. + """Begin enrollment. + + Two disjoint lanes: ``mfa_token`` (forced enrollment — the token was minted + seconds after a password verify, so it is its own freshness proof) or an + authenticated settings-flow enrollment, which must carry a fresh re-auth + proof — ``password``, or a ``reauth``-ceremony ``assertion`` when adding a + passkey beside an existing one. Attributes: mfa_token (None | str | Unset): Enrollment token from a login that returned mfa_enrollment_required + password (None | str | Unset): Current password — settings-lane re-authentication + assertion (None | PasskeyRegisterOptionsRequestAssertionType0 | Unset): Fresh WebAuthn assertion from the re- + auth ceremony (settings lane) """ mfa_token: None | str | Unset = UNSET + password: None | str | Unset = UNSET + assertion: None | PasskeyRegisterOptionsRequestAssertionType0 | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: + from ..models.passkey_register_options_request_assertion_type_0 import ( + PasskeyRegisterOptionsRequestAssertionType0, + ) + mfa_token: None | str | Unset if isinstance(self.mfa_token, Unset): mfa_token = UNSET else: mfa_token = self.mfa_token + password: None | str | Unset + if isinstance(self.password, Unset): + password = UNSET + else: + password = self.password + + assertion: dict[str, Any] | None | Unset + if isinstance(self.assertion, Unset): + assertion = UNSET + elif isinstance(self.assertion, PasskeyRegisterOptionsRequestAssertionType0): + assertion = self.assertion.to_dict() + else: + assertion = self.assertion + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) if mfa_token is not UNSET: field_dict["mfa_token"] = mfa_token + if password is not UNSET: + field_dict["password"] = password + if assertion is not UNSET: + field_dict["assertion"] = assertion return field_dict @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.passkey_register_options_request_assertion_type_0 import ( + PasskeyRegisterOptionsRequestAssertionType0, + ) + d = dict(src_dict) def _parse_mfa_token(data: object) -> None | str | Unset: @@ -51,8 +93,38 @@ def _parse_mfa_token(data: object) -> None | str | Unset: mfa_token = _parse_mfa_token(d.pop("mfa_token", UNSET)) + def _parse_password(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + password = _parse_password(d.pop("password", UNSET)) + + def _parse_assertion( + data: object, + ) -> None | PasskeyRegisterOptionsRequestAssertionType0 | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + assertion_type_0 = PasskeyRegisterOptionsRequestAssertionType0.from_dict(data) + + return assertion_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | PasskeyRegisterOptionsRequestAssertionType0 | Unset, data) + + assertion = _parse_assertion(d.pop("assertion", UNSET)) + passkey_register_options_request = cls( mfa_token=mfa_token, + password=password, + assertion=assertion, ) passkey_register_options_request.additional_properties = d diff --git a/robosystems_client/models/passkey_register_options_request_assertion_type_0.py b/robosystems_client/models/passkey_register_options_request_assertion_type_0.py new file mode 100644 index 0000000..7512ff8 --- /dev/null +++ b/robosystems_client/models/passkey_register_options_request_assertion_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PasskeyRegisterOptionsRequestAssertionType0") + + +@_attrs_define +class PasskeyRegisterOptionsRequestAssertionType0: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + passkey_register_options_request_assertion_type_0 = cls() + + passkey_register_options_request_assertion_type_0.additional_properties = d + return passkey_register_options_request_assertion_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties