diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1ca0ca2..ed91b37 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -21,7 +21,7 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/beeper-desktop-api-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install Rye
run: |
@@ -46,7 +46,7 @@ jobs:
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/beeper-desktop-api-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install Rye
run: |
@@ -67,7 +67,7 @@ jobs:
github.repository == 'stainless-sdks/beeper-desktop-api-python' &&
!startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
- uses: actions/github-script@v8
+ uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: core.setOutput('github_token', await core.getIDToken());
@@ -87,7 +87,7 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/beeper-desktop-api-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install Rye
run: |
diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml
index 54361b5..4954ee6 100644
--- a/.github/workflows/publish-pypi.yml
+++ b/.github/workflows/publish-pypi.yml
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install Rye
run: |
diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml
index 2d24407..0fe0ce0 100644
--- a/.github/workflows/release-doctor.yml
+++ b/.github/workflows/release-doctor.yml
@@ -12,7 +12,7 @@ jobs:
if: github.repository == 'beeper/desktop-api-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check release environment
run: |
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 8e76abb..4808d97 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "5.0.0"
+ ".": "5.1.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 2dd3fee..a6a4fc8 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 30
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-c08c14bb754b4cb0e02b21fabb680469368286be339dec0aaa8c69d04a1f021a.yml
-openapi_spec_hash: a10246aaf7cdc33b682fc245bd5f893b
-config_hash: 72f9d43b9b51a5da912e9f3730e53ae2
+configured_endpoints: 72
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-0427b028ffd00b4f8b75084116f801658d0279117b2d0e522d1f257c998f1fd0.yml
+openapi_spec_hash: af3ed0745fca6831cf2540c36050d4e6
+config_hash: fbf60dd7c0de7e17c7e2bb0ee09e9937
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 03fd832..0bce076 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## 5.1.0 (2026-05-16)
+
+Full Changelog: [v5.0.0...v5.1.0](https://github.com/beeper/desktop-api-python/compare/v5.0.0...v5.1.0)
+
+### Features
+
+* **internal/types:** support eagerly validating pydantic iterators ([1850c8a](https://github.com/beeper/desktop-api-python/commit/1850c8a7b7d3e45407524a6ebffe902d4a3f8a71))
+
+
+### Bug Fixes
+
+* **client:** add missing f-string prefix in file type error message ([78424e2](https://github.com/beeper/desktop-api-python/commit/78424e24ad4e1f336f843222ff19bf70a50f073f))
+
## 5.0.0 (2026-05-06)
Full Changelog: [v4.3.0...v5.0.0](https://github.com/beeper/desktop-api-python/compare/v4.3.0...v5.0.0)
diff --git a/api.md b/api.md
index 4818056..7ba1634 100644
--- a/api.md
+++ b/api.md
@@ -1,7 +1,7 @@
# Shared Types
```python
-from beeper_desktop_api.types import Attachment, Error, Message, Reaction, User
+from beeper_desktop_api.types import AppStateSnapshot, Attachment, Error, Message, Reaction, User
```
# BeeperDesktop
@@ -42,6 +42,18 @@ Methods:
- client.accounts.contacts.list(account_id, \*\*params) -> SyncCursorSearch[User]
- client.accounts.contacts.search(account_id, \*\*params) -> ContactSearchResponse
+# Bridges
+
+Types:
+
+```python
+from beeper_desktop_api.types import BridgeAvailability, BridgeListResponse
+```
+
+Methods:
+
+- client.bridges.list() -> BridgeListResponse
+
# Chats
Types:
@@ -132,3 +144,266 @@ from beeper_desktop_api.types import InfoRetrieveResponse
Methods:
- client.info.retrieve() -> InfoRetrieveResponse
+
+# App
+
+Types:
+
+```python
+from beeper_desktop_api.types import (
+ LoginRegistrationRequiredResponse,
+ LoginResponse,
+ LoginResponseOutput,
+ RecoveryCodeResetResponse,
+ StartVerificationResponse,
+ StateMutationResponse,
+ AppStatusResponse,
+)
+```
+
+Methods:
+
+- client.app.status() -> AppStatusResponse
+
+## Login
+
+Types:
+
+```python
+from beeper_desktop_api.types.app import (
+ LoginRegisterResponse,
+ LoginResponseResponse,
+ LoginStartResponse,
+)
+```
+
+Methods:
+
+- client.app.login.email(\*\*params) -> object
+- client.app.login.register(\*\*params) -> LoginRegisterResponse
+- client.app.login.response(\*\*params) -> LoginResponseResponse
+- client.app.login.start() -> LoginStartResponse
+
+## E2ee
+
+### RecoveryCode
+
+Types:
+
+```python
+from beeper_desktop_api.types.app.e2ee import (
+ RecoveryCodeMarkBackedUpResponse,
+ RecoveryCodeVerifyResponse,
+)
+```
+
+Methods:
+
+- client.app.e2ee.recovery_code.mark_backed_up() -> RecoveryCodeMarkBackedUpResponse
+- client.app.e2ee.recovery_code.verify(\*\*params) -> RecoveryCodeVerifyResponse
+
+#### Reset
+
+Types:
+
+```python
+from beeper_desktop_api.types.app.e2ee.recovery_code import (
+ ResetCreateResponse,
+ ResetConfirmResponse,
+)
+```
+
+Methods:
+
+- client.app.e2ee.recovery_code.reset.create(\*\*params) -> ResetCreateResponse
+- client.app.e2ee.recovery_code.reset.confirm(\*\*params) -> ResetConfirmResponse
+
+### Verification
+
+Types:
+
+```python
+from beeper_desktop_api.types.app.e2ee import (
+ VerificationCreateResponse,
+ VerificationAcceptResponse,
+ VerificationCancelResponse,
+)
+```
+
+Methods:
+
+- client.app.e2ee.verification.create(\*\*params) -> VerificationCreateResponse
+- client.app.e2ee.verification.accept(verification_id) -> VerificationAcceptResponse
+- client.app.e2ee.verification.cancel(verification_id, \*\*params) -> VerificationCancelResponse
+
+#### Qr
+
+Types:
+
+```python
+from beeper_desktop_api.types.app.e2ee.verification import QrConfirmScannedResponse, QrScanResponse
+```
+
+Methods:
+
+- client.app.e2ee.verification.qr.confirm_scanned(verification_id) -> QrConfirmScannedResponse
+- client.app.e2ee.verification.qr.scan(\*\*params) -> QrScanResponse
+
+#### Sas
+
+Types:
+
+```python
+from beeper_desktop_api.types.app.e2ee.verification import SaConfirmResponse, SaStartResponse
+```
+
+Methods:
+
+- client.app.e2ee.verification.sas.confirm(verification_id) -> SaConfirmResponse
+- client.app.e2ee.verification.sas.start(verification_id) -> SaStartResponse
+
+# Matrix
+
+## Users
+
+Types:
+
+```python
+from beeper_desktop_api.types.matrix import UserRetrieveProfileResponse
+```
+
+Methods:
+
+- client.matrix.users.retrieve_profile(user_id) -> UserRetrieveProfileResponse
+
+### AccountData
+
+Methods:
+
+- client.matrix.users.account_data.retrieve(type, \*, user_id) -> object
+- client.matrix.users.account_data.update(type, \*, user_id, \*\*params) -> object
+
+## Rooms
+
+Types:
+
+```python
+from beeper_desktop_api.types.matrix import RoomCreateResponse, RoomJoinResponse
+```
+
+Methods:
+
+- client.matrix.rooms.create(\*\*params) -> RoomCreateResponse
+- client.matrix.rooms.join(room_id_or_alias, \*\*params) -> RoomJoinResponse
+- client.matrix.rooms.leave(room_id, \*\*params) -> object
+
+### AccountData
+
+Methods:
+
+- client.matrix.rooms.account_data.retrieve(type, \*, user_id, room_id) -> object
+- client.matrix.rooms.account_data.update(type, \*, user_id, room_id, \*\*params) -> object
+
+### State
+
+Types:
+
+```python
+from beeper_desktop_api.types.matrix.rooms import StateRetrieveResponse, StateListResponse
+```
+
+Methods:
+
+- client.matrix.rooms.state.retrieve(state_key, \*, room_id, event_type, \*\*params) -> StateRetrieveResponse
+- client.matrix.rooms.state.list(room_id) -> StateListResponse
+
+### Events
+
+Types:
+
+```python
+from beeper_desktop_api.types.matrix.rooms import EventRetrieveResponse
+```
+
+Methods:
+
+- client.matrix.rooms.events.retrieve(event_id, \*, room_id) -> EventRetrieveResponse
+
+## Bridges
+
+### Auth
+
+Types:
+
+```python
+from beeper_desktop_api.types.matrix.bridges import (
+ AuthListFlowsResponse,
+ AuthListLoginsResponse,
+ AuthStartLoginResponse,
+ AuthSubmitCookiesResponse,
+ AuthSubmitUserInputResponse,
+ AuthWaitForStepResponse,
+ AuthWhoamiResponse,
+)
+```
+
+Methods:
+
+- client.matrix.bridges.auth.list_flows(bridge_id) -> AuthListFlowsResponse
+- client.matrix.bridges.auth.list_logins(bridge_id) -> AuthListLoginsResponse
+- client.matrix.bridges.auth.logout(login_id, \*, bridge_id) -> object
+- client.matrix.bridges.auth.start_login(flow_id, \*, bridge_id, \*\*params) -> AuthStartLoginResponse
+- client.matrix.bridges.auth.submit_cookies(step_id, \*, bridge_id, login_process_id, \*\*params) -> AuthSubmitCookiesResponse
+- client.matrix.bridges.auth.submit_user_input(step_id, \*, bridge_id, login_process_id, \*\*params) -> AuthSubmitUserInputResponse
+- client.matrix.bridges.auth.wait_for_step(step_id, \*, bridge_id, login_process_id) -> AuthWaitForStepResponse
+- client.matrix.bridges.auth.whoami(bridge_id) -> AuthWhoamiResponse
+
+### Contacts
+
+Types:
+
+```python
+from beeper_desktop_api.types.matrix.bridges import ContactListResponse
+```
+
+Methods:
+
+- client.matrix.bridges.contacts.list(bridge_id, \*\*params) -> ContactListResponse
+
+### Users
+
+Types:
+
+```python
+from beeper_desktop_api.types.matrix.bridges import UserResolveResponse, UserSearchResponse
+```
+
+Methods:
+
+- client.matrix.bridges.users.resolve(identifier, \*, bridge_id, \*\*params) -> UserResolveResponse
+- client.matrix.bridges.users.search(bridge_id, \*\*params) -> UserSearchResponse
+
+### Rooms
+
+Types:
+
+```python
+from beeper_desktop_api.types.matrix.bridges import RoomCreateDmResponse, RoomCreateGroupResponse
+```
+
+Methods:
+
+- client.matrix.bridges.rooms.create_dm(identifier, \*, bridge_id, \*\*params) -> RoomCreateDmResponse
+- client.matrix.bridges.rooms.create_group(group_type, \*, bridge_id, \*\*params) -> RoomCreateGroupResponse
+
+### Capabilities
+
+Types:
+
+```python
+from beeper_desktop_api.types.matrix.bridges import CapabilityRetrieveResponse
+```
+
+Methods:
+
+- client.matrix.bridges.capabilities.retrieve(bridge_id) -> CapabilityRetrieveResponse
diff --git a/pyproject.toml b/pyproject.toml
index 83d327e..5ce2088 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "beeper_desktop_api"
-version = "5.0.0"
+version = "5.1.0"
description = "The official Python library for the beeperdesktop API"
dynamic = ["readme"]
license = "MIT"
diff --git a/src/beeper_desktop_api/_client.py b/src/beeper_desktop_api/_client.py
index 6c43fcb..9327a44 100644
--- a/src/beeper_desktop_api/_client.py
+++ b/src/beeper_desktop_api/_client.py
@@ -52,11 +52,14 @@
from .types.search_response import SearchResponse
if TYPE_CHECKING:
- from .resources import info, chats, assets, accounts, messages
+ from .resources import app, info, chats, assets, matrix, bridges, accounts, messages
from .resources.info import InfoResource, AsyncInfoResource
from .resources.assets import AssetsResource, AsyncAssetsResource
+ from .resources.app.app import AppResource, AsyncAppResource
+ from .resources.bridges import BridgesResource, AsyncBridgesResource
from .resources.messages import MessagesResource, AsyncMessagesResource
from .resources.chats.chats import ChatsResource, AsyncChatsResource
+ from .resources.matrix.matrix import MatrixResource, AsyncMatrixResource
from .resources.accounts.accounts import AccountsResource, AsyncAccountsResource
__all__ = [
@@ -142,6 +145,13 @@ def accounts(self) -> AccountsResource:
return AccountsResource(self)
+ @cached_property
+ def bridges(self) -> BridgesResource:
+ """Manage bridge-backed account types and account availability"""
+ from .resources.bridges import BridgesResource
+
+ return BridgesResource(self)
+
@cached_property
def chats(self) -> ChatsResource:
"""Manage chats"""
@@ -173,6 +183,20 @@ def info(self) -> InfoResource:
return InfoResource(self)
+ @cached_property
+ def app(self) -> AppResource:
+ """Manage Beeper app login and encrypted messaging setup"""
+ from .resources.app import AppResource
+
+ return AppResource(self)
+
+ @cached_property
+ def matrix(self) -> MatrixResource:
+ """Matrix-compatible APIs for accounts, rooms, and connected network bridges."""
+ from .resources.matrix import MatrixResource
+
+ return MatrixResource(self)
+
@cached_property
def with_raw_response(self) -> BeeperDesktopWithRawResponse:
return BeeperDesktopWithRawResponse(self)
@@ -454,6 +478,13 @@ def accounts(self) -> AsyncAccountsResource:
return AsyncAccountsResource(self)
+ @cached_property
+ def bridges(self) -> AsyncBridgesResource:
+ """Manage bridge-backed account types and account availability"""
+ from .resources.bridges import AsyncBridgesResource
+
+ return AsyncBridgesResource(self)
+
@cached_property
def chats(self) -> AsyncChatsResource:
"""Manage chats"""
@@ -485,6 +516,20 @@ def info(self) -> AsyncInfoResource:
return AsyncInfoResource(self)
+ @cached_property
+ def app(self) -> AsyncAppResource:
+ """Manage Beeper app login and encrypted messaging setup"""
+ from .resources.app import AsyncAppResource
+
+ return AsyncAppResource(self)
+
+ @cached_property
+ def matrix(self) -> AsyncMatrixResource:
+ """Matrix-compatible APIs for accounts, rooms, and connected network bridges."""
+ from .resources.matrix import AsyncMatrixResource
+
+ return AsyncMatrixResource(self)
+
@cached_property
def with_raw_response(self) -> AsyncBeeperDesktopWithRawResponse:
return AsyncBeeperDesktopWithRawResponse(self)
@@ -715,6 +760,13 @@ def accounts(self) -> accounts.AccountsResourceWithRawResponse:
return AccountsResourceWithRawResponse(self._client.accounts)
+ @cached_property
+ def bridges(self) -> bridges.BridgesResourceWithRawResponse:
+ """Manage bridge-backed account types and account availability"""
+ from .resources.bridges import BridgesResourceWithRawResponse
+
+ return BridgesResourceWithRawResponse(self._client.bridges)
+
@cached_property
def chats(self) -> chats.ChatsResourceWithRawResponse:
"""Manage chats"""
@@ -746,6 +798,20 @@ def info(self) -> info.InfoResourceWithRawResponse:
return InfoResourceWithRawResponse(self._client.info)
+ @cached_property
+ def app(self) -> app.AppResourceWithRawResponse:
+ """Manage Beeper app login and encrypted messaging setup"""
+ from .resources.app import AppResourceWithRawResponse
+
+ return AppResourceWithRawResponse(self._client.app)
+
+ @cached_property
+ def matrix(self) -> matrix.MatrixResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts, rooms, and connected network bridges."""
+ from .resources.matrix import MatrixResourceWithRawResponse
+
+ return MatrixResourceWithRawResponse(self._client.matrix)
+
class AsyncBeeperDesktopWithRawResponse:
_client: AsyncBeeperDesktop
@@ -767,6 +833,13 @@ def accounts(self) -> accounts.AsyncAccountsResourceWithRawResponse:
return AsyncAccountsResourceWithRawResponse(self._client.accounts)
+ @cached_property
+ def bridges(self) -> bridges.AsyncBridgesResourceWithRawResponse:
+ """Manage bridge-backed account types and account availability"""
+ from .resources.bridges import AsyncBridgesResourceWithRawResponse
+
+ return AsyncBridgesResourceWithRawResponse(self._client.bridges)
+
@cached_property
def chats(self) -> chats.AsyncChatsResourceWithRawResponse:
"""Manage chats"""
@@ -798,6 +871,20 @@ def info(self) -> info.AsyncInfoResourceWithRawResponse:
return AsyncInfoResourceWithRawResponse(self._client.info)
+ @cached_property
+ def app(self) -> app.AsyncAppResourceWithRawResponse:
+ """Manage Beeper app login and encrypted messaging setup"""
+ from .resources.app import AsyncAppResourceWithRawResponse
+
+ return AsyncAppResourceWithRawResponse(self._client.app)
+
+ @cached_property
+ def matrix(self) -> matrix.AsyncMatrixResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts, rooms, and connected network bridges."""
+ from .resources.matrix import AsyncMatrixResourceWithRawResponse
+
+ return AsyncMatrixResourceWithRawResponse(self._client.matrix)
+
class BeeperDesktopWithStreamedResponse:
_client: BeeperDesktop
@@ -819,6 +906,13 @@ def accounts(self) -> accounts.AccountsResourceWithStreamingResponse:
return AccountsResourceWithStreamingResponse(self._client.accounts)
+ @cached_property
+ def bridges(self) -> bridges.BridgesResourceWithStreamingResponse:
+ """Manage bridge-backed account types and account availability"""
+ from .resources.bridges import BridgesResourceWithStreamingResponse
+
+ return BridgesResourceWithStreamingResponse(self._client.bridges)
+
@cached_property
def chats(self) -> chats.ChatsResourceWithStreamingResponse:
"""Manage chats"""
@@ -850,6 +944,20 @@ def info(self) -> info.InfoResourceWithStreamingResponse:
return InfoResourceWithStreamingResponse(self._client.info)
+ @cached_property
+ def app(self) -> app.AppResourceWithStreamingResponse:
+ """Manage Beeper app login and encrypted messaging setup"""
+ from .resources.app import AppResourceWithStreamingResponse
+
+ return AppResourceWithStreamingResponse(self._client.app)
+
+ @cached_property
+ def matrix(self) -> matrix.MatrixResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts, rooms, and connected network bridges."""
+ from .resources.matrix import MatrixResourceWithStreamingResponse
+
+ return MatrixResourceWithStreamingResponse(self._client.matrix)
+
class AsyncBeeperDesktopWithStreamedResponse:
_client: AsyncBeeperDesktop
@@ -871,6 +979,13 @@ def accounts(self) -> accounts.AsyncAccountsResourceWithStreamingResponse:
return AsyncAccountsResourceWithStreamingResponse(self._client.accounts)
+ @cached_property
+ def bridges(self) -> bridges.AsyncBridgesResourceWithStreamingResponse:
+ """Manage bridge-backed account types and account availability"""
+ from .resources.bridges import AsyncBridgesResourceWithStreamingResponse
+
+ return AsyncBridgesResourceWithStreamingResponse(self._client.bridges)
+
@cached_property
def chats(self) -> chats.AsyncChatsResourceWithStreamingResponse:
"""Manage chats"""
@@ -902,6 +1017,20 @@ def info(self) -> info.AsyncInfoResourceWithStreamingResponse:
return AsyncInfoResourceWithStreamingResponse(self._client.info)
+ @cached_property
+ def app(self) -> app.AsyncAppResourceWithStreamingResponse:
+ """Manage Beeper app login and encrypted messaging setup"""
+ from .resources.app import AsyncAppResourceWithStreamingResponse
+
+ return AsyncAppResourceWithStreamingResponse(self._client.app)
+
+ @cached_property
+ def matrix(self) -> matrix.AsyncMatrixResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts, rooms, and connected network bridges."""
+ from .resources.matrix import AsyncMatrixResourceWithStreamingResponse
+
+ return AsyncMatrixResourceWithStreamingResponse(self._client.matrix)
+
Client = BeeperDesktop
diff --git a/src/beeper_desktop_api/_files.py b/src/beeper_desktop_api/_files.py
index 8a371d3..be8e0e1 100644
--- a/src/beeper_desktop_api/_files.py
+++ b/src/beeper_desktop_api/_files.py
@@ -99,7 +99,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles
elif is_sequence_t(files):
files = [(key, await _async_transform_file(file)) for key, file in files]
else:
- raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence")
+ raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence")
return files
diff --git a/src/beeper_desktop_api/_models.py b/src/beeper_desktop_api/_models.py
index e22dd2a..69f41a6 100644
--- a/src/beeper_desktop_api/_models.py
+++ b/src/beeper_desktop_api/_models.py
@@ -25,7 +25,9 @@
ClassVar,
Protocol,
Required,
+ Annotated,
ParamSpec,
+ TypeAlias,
TypedDict,
TypeGuard,
final,
@@ -79,7 +81,15 @@
from ._constants import RAW_RESPONSE_HEADER
if TYPE_CHECKING:
+ from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler
+ from pydantic_core import CoreSchema, core_schema
from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema
+else:
+ try:
+ from pydantic_core import CoreSchema, core_schema
+ except ImportError:
+ CoreSchema = None
+ core_schema = None
__all__ = ["BaseModel", "GenericModel"]
@@ -396,6 +406,76 @@ def model_dump_json(
)
+class _EagerIterable(list[_T], Generic[_T]):
+ """
+ Accepts any Iterable[T] input (including generators), consumes it
+ eagerly, and validates all items upfront.
+
+ Validation preserves the original container type where possible
+ (e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON)
+ always emits a list — round-tripping through model_dump() will not
+ restore the original container type.
+ """
+
+ @classmethod
+ def __get_pydantic_core_schema__(
+ cls,
+ source_type: Any,
+ handler: GetCoreSchemaHandler,
+ ) -> CoreSchema:
+ (item_type,) = get_args(source_type) or (Any,)
+ item_schema: CoreSchema = handler.generate_schema(item_type)
+ list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema)
+
+ return core_schema.no_info_wrap_validator_function(
+ cls._validate,
+ list_of_items_schema,
+ serialization=core_schema.plain_serializer_function_ser_schema(
+ cls._serialize,
+ info_arg=False,
+ ),
+ )
+
+ @staticmethod
+ def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any:
+ original_type: type[Any] = type(v)
+
+ # Normalize to list so list_schema can validate each item
+ if isinstance(v, list):
+ items: list[_T] = v
+ else:
+ try:
+ items = list(v)
+ except TypeError as e:
+ raise TypeError("Value is not iterable") from e
+
+ # Validate items against the inner schema
+ validated: list[_T] = handler(items)
+
+ # Reconstruct original container type
+ if original_type is list:
+ return validated
+ # str(list) produces the list's repr, not a string built from items,
+ # so skip reconstruction for str and its subclasses.
+ if issubclass(original_type, str):
+ return validated
+ try:
+ return original_type(validated)
+ except (TypeError, ValueError):
+ # If the type cannot be reconstructed, just return the validated list
+ return validated
+
+ @staticmethod
+ def _serialize(v: Iterable[_T]) -> list[_T]:
+ """Always serialize as a list so Pydantic's JSON encoder is happy."""
+ if isinstance(v, list):
+ return v
+ return list(v)
+
+
+EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable]
+
+
def _construct_field(value: object, field: FieldInfo, key: str) -> object:
if value is None:
return field_get_default(field)
diff --git a/src/beeper_desktop_api/_version.py b/src/beeper_desktop_api/_version.py
index 60fb169..701658d 100644
--- a/src/beeper_desktop_api/_version.py
+++ b/src/beeper_desktop_api/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "beeper_desktop_api"
-__version__ = "5.0.0" # x-release-please-version
+__version__ = "5.1.0" # x-release-please-version
diff --git a/src/beeper_desktop_api/resources/__init__.py b/src/beeper_desktop_api/resources/__init__.py
index a066e9b..26dee5c 100644
--- a/src/beeper_desktop_api/resources/__init__.py
+++ b/src/beeper_desktop_api/resources/__init__.py
@@ -1,5 +1,13 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+from .app import (
+ AppResource,
+ AsyncAppResource,
+ AppResourceWithRawResponse,
+ AsyncAppResourceWithRawResponse,
+ AppResourceWithStreamingResponse,
+ AsyncAppResourceWithStreamingResponse,
+)
from .info import (
InfoResource,
AsyncInfoResource,
@@ -24,6 +32,22 @@
AssetsResourceWithStreamingResponse,
AsyncAssetsResourceWithStreamingResponse,
)
+from .matrix import (
+ MatrixResource,
+ AsyncMatrixResource,
+ MatrixResourceWithRawResponse,
+ AsyncMatrixResourceWithRawResponse,
+ MatrixResourceWithStreamingResponse,
+ AsyncMatrixResourceWithStreamingResponse,
+)
+from .bridges import (
+ BridgesResource,
+ AsyncBridgesResource,
+ BridgesResourceWithRawResponse,
+ AsyncBridgesResourceWithRawResponse,
+ BridgesResourceWithStreamingResponse,
+ AsyncBridgesResourceWithStreamingResponse,
+)
from .accounts import (
AccountsResource,
AsyncAccountsResource,
@@ -48,6 +72,12 @@
"AsyncAccountsResourceWithRawResponse",
"AccountsResourceWithStreamingResponse",
"AsyncAccountsResourceWithStreamingResponse",
+ "BridgesResource",
+ "AsyncBridgesResource",
+ "BridgesResourceWithRawResponse",
+ "AsyncBridgesResourceWithRawResponse",
+ "BridgesResourceWithStreamingResponse",
+ "AsyncBridgesResourceWithStreamingResponse",
"ChatsResource",
"AsyncChatsResource",
"ChatsResourceWithRawResponse",
@@ -72,4 +102,16 @@
"AsyncInfoResourceWithRawResponse",
"InfoResourceWithStreamingResponse",
"AsyncInfoResourceWithStreamingResponse",
+ "AppResource",
+ "AsyncAppResource",
+ "AppResourceWithRawResponse",
+ "AsyncAppResourceWithRawResponse",
+ "AppResourceWithStreamingResponse",
+ "AsyncAppResourceWithStreamingResponse",
+ "MatrixResource",
+ "AsyncMatrixResource",
+ "MatrixResourceWithRawResponse",
+ "AsyncMatrixResourceWithRawResponse",
+ "MatrixResourceWithStreamingResponse",
+ "AsyncMatrixResourceWithStreamingResponse",
]
diff --git a/src/beeper_desktop_api/resources/app/__init__.py b/src/beeper_desktop_api/resources/app/__init__.py
new file mode 100644
index 0000000..a21f690
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/__init__.py
@@ -0,0 +1,47 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .app import (
+ AppResource,
+ AsyncAppResource,
+ AppResourceWithRawResponse,
+ AsyncAppResourceWithRawResponse,
+ AppResourceWithStreamingResponse,
+ AsyncAppResourceWithStreamingResponse,
+)
+from .e2ee import (
+ E2eeResource,
+ AsyncE2eeResource,
+ E2eeResourceWithRawResponse,
+ AsyncE2eeResourceWithRawResponse,
+ E2eeResourceWithStreamingResponse,
+ AsyncE2eeResourceWithStreamingResponse,
+)
+from .login import (
+ LoginResource,
+ AsyncLoginResource,
+ LoginResourceWithRawResponse,
+ AsyncLoginResourceWithRawResponse,
+ LoginResourceWithStreamingResponse,
+ AsyncLoginResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "LoginResource",
+ "AsyncLoginResource",
+ "LoginResourceWithRawResponse",
+ "AsyncLoginResourceWithRawResponse",
+ "LoginResourceWithStreamingResponse",
+ "AsyncLoginResourceWithStreamingResponse",
+ "E2eeResource",
+ "AsyncE2eeResource",
+ "E2eeResourceWithRawResponse",
+ "AsyncE2eeResourceWithRawResponse",
+ "E2eeResourceWithStreamingResponse",
+ "AsyncE2eeResourceWithStreamingResponse",
+ "AppResource",
+ "AsyncAppResource",
+ "AppResourceWithRawResponse",
+ "AsyncAppResourceWithRawResponse",
+ "AppResourceWithStreamingResponse",
+ "AsyncAppResourceWithStreamingResponse",
+]
diff --git a/src/beeper_desktop_api/resources/app/app.py b/src/beeper_desktop_api/resources/app/app.py
new file mode 100644
index 0000000..73858b9
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/app.py
@@ -0,0 +1,223 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from .login import (
+ LoginResource,
+ AsyncLoginResource,
+ LoginResourceWithRawResponse,
+ AsyncLoginResourceWithRawResponse,
+ LoginResourceWithStreamingResponse,
+ AsyncLoginResourceWithStreamingResponse,
+)
+from ..._types import Body, Query, Headers, NotGiven, not_given
+from ..._compat import cached_property
+from .e2ee.e2ee import (
+ E2eeResource,
+ AsyncE2eeResource,
+ E2eeResourceWithRawResponse,
+ AsyncE2eeResourceWithRawResponse,
+ E2eeResourceWithStreamingResponse,
+ AsyncE2eeResourceWithStreamingResponse,
+)
+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.app_status_response import AppStatusResponse
+
+__all__ = ["AppResource", "AsyncAppResource"]
+
+
+class AppResource(SyncAPIResource):
+ """Manage Beeper app login and encrypted messaging setup"""
+
+ @cached_property
+ def login(self) -> LoginResource:
+ """Complete first-party Beeper app login"""
+ return LoginResource(self._client)
+
+ @cached_property
+ def e2ee(self) -> E2eeResource:
+ """Manage encrypted messaging setup"""
+ return E2eeResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AppResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AppResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AppResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AppResourceWithStreamingResponse(self)
+
+ def status(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AppStatusResponse:
+ """
+ Return the current Beeper Desktop sign-in and encrypted messaging setup state.
+ This endpoint is public before sign-in so apps can discover that login is
+ needed; after sign-in, pass a read token.
+ """
+ return self._get(
+ "/v1/app/status",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AppStatusResponse,
+ )
+
+
+class AsyncAppResource(AsyncAPIResource):
+ """Manage Beeper app login and encrypted messaging setup"""
+
+ @cached_property
+ def login(self) -> AsyncLoginResource:
+ """Complete first-party Beeper app login"""
+ return AsyncLoginResource(self._client)
+
+ @cached_property
+ def e2ee(self) -> AsyncE2eeResource:
+ """Manage encrypted messaging setup"""
+ return AsyncE2eeResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncAppResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncAppResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAppResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncAppResourceWithStreamingResponse(self)
+
+ async def status(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AppStatusResponse:
+ """
+ Return the current Beeper Desktop sign-in and encrypted messaging setup state.
+ This endpoint is public before sign-in so apps can discover that login is
+ needed; after sign-in, pass a read token.
+ """
+ return await self._get(
+ "/v1/app/status",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AppStatusResponse,
+ )
+
+
+class AppResourceWithRawResponse:
+ def __init__(self, app: AppResource) -> None:
+ self._app = app
+
+ self.status = to_raw_response_wrapper(
+ app.status,
+ )
+
+ @cached_property
+ def login(self) -> LoginResourceWithRawResponse:
+ """Complete first-party Beeper app login"""
+ return LoginResourceWithRawResponse(self._app.login)
+
+ @cached_property
+ def e2ee(self) -> E2eeResourceWithRawResponse:
+ """Manage encrypted messaging setup"""
+ return E2eeResourceWithRawResponse(self._app.e2ee)
+
+
+class AsyncAppResourceWithRawResponse:
+ def __init__(self, app: AsyncAppResource) -> None:
+ self._app = app
+
+ self.status = async_to_raw_response_wrapper(
+ app.status,
+ )
+
+ @cached_property
+ def login(self) -> AsyncLoginResourceWithRawResponse:
+ """Complete first-party Beeper app login"""
+ return AsyncLoginResourceWithRawResponse(self._app.login)
+
+ @cached_property
+ def e2ee(self) -> AsyncE2eeResourceWithRawResponse:
+ """Manage encrypted messaging setup"""
+ return AsyncE2eeResourceWithRawResponse(self._app.e2ee)
+
+
+class AppResourceWithStreamingResponse:
+ def __init__(self, app: AppResource) -> None:
+ self._app = app
+
+ self.status = to_streamed_response_wrapper(
+ app.status,
+ )
+
+ @cached_property
+ def login(self) -> LoginResourceWithStreamingResponse:
+ """Complete first-party Beeper app login"""
+ return LoginResourceWithStreamingResponse(self._app.login)
+
+ @cached_property
+ def e2ee(self) -> E2eeResourceWithStreamingResponse:
+ """Manage encrypted messaging setup"""
+ return E2eeResourceWithStreamingResponse(self._app.e2ee)
+
+
+class AsyncAppResourceWithStreamingResponse:
+ def __init__(self, app: AsyncAppResource) -> None:
+ self._app = app
+
+ self.status = async_to_streamed_response_wrapper(
+ app.status,
+ )
+
+ @cached_property
+ def login(self) -> AsyncLoginResourceWithStreamingResponse:
+ """Complete first-party Beeper app login"""
+ return AsyncLoginResourceWithStreamingResponse(self._app.login)
+
+ @cached_property
+ def e2ee(self) -> AsyncE2eeResourceWithStreamingResponse:
+ """Manage encrypted messaging setup"""
+ return AsyncE2eeResourceWithStreamingResponse(self._app.e2ee)
diff --git a/src/beeper_desktop_api/resources/app/e2ee/__init__.py b/src/beeper_desktop_api/resources/app/e2ee/__init__.py
new file mode 100644
index 0000000..f7fa574
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/e2ee/__init__.py
@@ -0,0 +1,47 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .e2ee import (
+ E2eeResource,
+ AsyncE2eeResource,
+ E2eeResourceWithRawResponse,
+ AsyncE2eeResourceWithRawResponse,
+ E2eeResourceWithStreamingResponse,
+ AsyncE2eeResourceWithStreamingResponse,
+)
+from .verification import (
+ VerificationResource,
+ AsyncVerificationResource,
+ VerificationResourceWithRawResponse,
+ AsyncVerificationResourceWithRawResponse,
+ VerificationResourceWithStreamingResponse,
+ AsyncVerificationResourceWithStreamingResponse,
+)
+from .recovery_code import (
+ RecoveryCodeResource,
+ AsyncRecoveryCodeResource,
+ RecoveryCodeResourceWithRawResponse,
+ AsyncRecoveryCodeResourceWithRawResponse,
+ RecoveryCodeResourceWithStreamingResponse,
+ AsyncRecoveryCodeResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "RecoveryCodeResource",
+ "AsyncRecoveryCodeResource",
+ "RecoveryCodeResourceWithRawResponse",
+ "AsyncRecoveryCodeResourceWithRawResponse",
+ "RecoveryCodeResourceWithStreamingResponse",
+ "AsyncRecoveryCodeResourceWithStreamingResponse",
+ "VerificationResource",
+ "AsyncVerificationResource",
+ "VerificationResourceWithRawResponse",
+ "AsyncVerificationResourceWithRawResponse",
+ "VerificationResourceWithStreamingResponse",
+ "AsyncVerificationResourceWithStreamingResponse",
+ "E2eeResource",
+ "AsyncE2eeResource",
+ "E2eeResourceWithRawResponse",
+ "AsyncE2eeResourceWithRawResponse",
+ "E2eeResourceWithStreamingResponse",
+ "AsyncE2eeResourceWithStreamingResponse",
+]
diff --git a/src/beeper_desktop_api/resources/app/e2ee/e2ee.py b/src/beeper_desktop_api/resources/app/e2ee/e2ee.py
new file mode 100644
index 0000000..285e853
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/e2ee/e2ee.py
@@ -0,0 +1,150 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from .verification.verification import (
+ VerificationResource,
+ AsyncVerificationResource,
+ VerificationResourceWithRawResponse,
+ AsyncVerificationResourceWithRawResponse,
+ VerificationResourceWithStreamingResponse,
+ AsyncVerificationResourceWithStreamingResponse,
+)
+from .recovery_code.recovery_code import (
+ RecoveryCodeResource,
+ AsyncRecoveryCodeResource,
+ RecoveryCodeResourceWithRawResponse,
+ AsyncRecoveryCodeResourceWithRawResponse,
+ RecoveryCodeResourceWithStreamingResponse,
+ AsyncRecoveryCodeResourceWithStreamingResponse,
+)
+
+__all__ = ["E2eeResource", "AsyncE2eeResource"]
+
+
+class E2eeResource(SyncAPIResource):
+ """Manage encrypted messaging setup"""
+
+ @cached_property
+ def recovery_code(self) -> RecoveryCodeResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return RecoveryCodeResource(self._client)
+
+ @cached_property
+ def verification(self) -> VerificationResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return VerificationResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> E2eeResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return E2eeResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> E2eeResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return E2eeResourceWithStreamingResponse(self)
+
+
+class AsyncE2eeResource(AsyncAPIResource):
+ """Manage encrypted messaging setup"""
+
+ @cached_property
+ def recovery_code(self) -> AsyncRecoveryCodeResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncRecoveryCodeResource(self._client)
+
+ @cached_property
+ def verification(self) -> AsyncVerificationResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncVerificationResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncE2eeResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncE2eeResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncE2eeResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncE2eeResourceWithStreamingResponse(self)
+
+
+class E2eeResourceWithRawResponse:
+ def __init__(self, e2ee: E2eeResource) -> None:
+ self._e2ee = e2ee
+
+ @cached_property
+ def recovery_code(self) -> RecoveryCodeResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return RecoveryCodeResourceWithRawResponse(self._e2ee.recovery_code)
+
+ @cached_property
+ def verification(self) -> VerificationResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return VerificationResourceWithRawResponse(self._e2ee.verification)
+
+
+class AsyncE2eeResourceWithRawResponse:
+ def __init__(self, e2ee: AsyncE2eeResource) -> None:
+ self._e2ee = e2ee
+
+ @cached_property
+ def recovery_code(self) -> AsyncRecoveryCodeResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncRecoveryCodeResourceWithRawResponse(self._e2ee.recovery_code)
+
+ @cached_property
+ def verification(self) -> AsyncVerificationResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncVerificationResourceWithRawResponse(self._e2ee.verification)
+
+
+class E2eeResourceWithStreamingResponse:
+ def __init__(self, e2ee: E2eeResource) -> None:
+ self._e2ee = e2ee
+
+ @cached_property
+ def recovery_code(self) -> RecoveryCodeResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return RecoveryCodeResourceWithStreamingResponse(self._e2ee.recovery_code)
+
+ @cached_property
+ def verification(self) -> VerificationResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return VerificationResourceWithStreamingResponse(self._e2ee.verification)
+
+
+class AsyncE2eeResourceWithStreamingResponse:
+ def __init__(self, e2ee: AsyncE2eeResource) -> None:
+ self._e2ee = e2ee
+
+ @cached_property
+ def recovery_code(self) -> AsyncRecoveryCodeResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncRecoveryCodeResourceWithStreamingResponse(self._e2ee.recovery_code)
+
+ @cached_property
+ def verification(self) -> AsyncVerificationResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncVerificationResourceWithStreamingResponse(self._e2ee.verification)
diff --git a/src/beeper_desktop_api/resources/app/e2ee/recovery_code/__init__.py b/src/beeper_desktop_api/resources/app/e2ee/recovery_code/__init__.py
new file mode 100644
index 0000000..f60d377
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/e2ee/recovery_code/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .reset import (
+ ResetResource,
+ AsyncResetResource,
+ ResetResourceWithRawResponse,
+ AsyncResetResourceWithRawResponse,
+ ResetResourceWithStreamingResponse,
+ AsyncResetResourceWithStreamingResponse,
+)
+from .recovery_code import (
+ RecoveryCodeResource,
+ AsyncRecoveryCodeResource,
+ RecoveryCodeResourceWithRawResponse,
+ AsyncRecoveryCodeResourceWithRawResponse,
+ RecoveryCodeResourceWithStreamingResponse,
+ AsyncRecoveryCodeResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "ResetResource",
+ "AsyncResetResource",
+ "ResetResourceWithRawResponse",
+ "AsyncResetResourceWithRawResponse",
+ "ResetResourceWithStreamingResponse",
+ "AsyncResetResourceWithStreamingResponse",
+ "RecoveryCodeResource",
+ "AsyncRecoveryCodeResource",
+ "RecoveryCodeResourceWithRawResponse",
+ "AsyncRecoveryCodeResourceWithRawResponse",
+ "RecoveryCodeResourceWithStreamingResponse",
+ "AsyncRecoveryCodeResourceWithStreamingResponse",
+]
diff --git a/src/beeper_desktop_api/resources/app/e2ee/recovery_code/recovery_code.py b/src/beeper_desktop_api/resources/app/e2ee/recovery_code/recovery_code.py
new file mode 100644
index 0000000..47a7804
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/e2ee/recovery_code/recovery_code.py
@@ -0,0 +1,264 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from .reset import (
+ ResetResource,
+ AsyncResetResource,
+ ResetResourceWithRawResponse,
+ AsyncResetResourceWithRawResponse,
+ ResetResourceWithStreamingResponse,
+ AsyncResetResourceWithStreamingResponse,
+)
+from ....._types import Body, Query, Headers, NotGiven, not_given
+from ....._utils import 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.app.e2ee import recovery_code_verify_params
+from .....types.app.e2ee.recovery_code_verify_response import RecoveryCodeVerifyResponse
+from .....types.app.e2ee.recovery_code_mark_backed_up_response import RecoveryCodeMarkBackedUpResponse
+
+__all__ = ["RecoveryCodeResource", "AsyncRecoveryCodeResource"]
+
+
+class RecoveryCodeResource(SyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def reset(self) -> ResetResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return ResetResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> RecoveryCodeResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return RecoveryCodeResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> RecoveryCodeResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return RecoveryCodeResourceWithStreamingResponse(self)
+
+ def mark_backed_up(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RecoveryCodeMarkBackedUpResponse:
+ """Record that the user saved their recovery key."""
+ return self._post(
+ "/v1/app/e2ee/recovery-code/mark-backed-up",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RecoveryCodeMarkBackedUpResponse,
+ )
+
+ def verify(
+ self,
+ *,
+ recovery_code: 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,
+ ) -> RecoveryCodeVerifyResponse:
+ """
+ Unlock encrypted messages with the user recovery key.
+
+ Args:
+ recovery_code: Recovery key saved by the user.
+
+ 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(
+ "/v1/app/e2ee/recovery-code/verify",
+ body=maybe_transform(
+ {"recovery_code": recovery_code}, recovery_code_verify_params.RecoveryCodeVerifyParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RecoveryCodeVerifyResponse,
+ )
+
+
+class AsyncRecoveryCodeResource(AsyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def reset(self) -> AsyncResetResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncResetResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncRecoveryCodeResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncRecoveryCodeResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncRecoveryCodeResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncRecoveryCodeResourceWithStreamingResponse(self)
+
+ async def mark_backed_up(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RecoveryCodeMarkBackedUpResponse:
+ """Record that the user saved their recovery key."""
+ return await self._post(
+ "/v1/app/e2ee/recovery-code/mark-backed-up",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RecoveryCodeMarkBackedUpResponse,
+ )
+
+ async def verify(
+ self,
+ *,
+ recovery_code: 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,
+ ) -> RecoveryCodeVerifyResponse:
+ """
+ Unlock encrypted messages with the user recovery key.
+
+ Args:
+ recovery_code: Recovery key saved by the user.
+
+ 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(
+ "/v1/app/e2ee/recovery-code/verify",
+ body=await async_maybe_transform(
+ {"recovery_code": recovery_code}, recovery_code_verify_params.RecoveryCodeVerifyParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RecoveryCodeVerifyResponse,
+ )
+
+
+class RecoveryCodeResourceWithRawResponse:
+ def __init__(self, recovery_code: RecoveryCodeResource) -> None:
+ self._recovery_code = recovery_code
+
+ self.mark_backed_up = to_raw_response_wrapper(
+ recovery_code.mark_backed_up,
+ )
+ self.verify = to_raw_response_wrapper(
+ recovery_code.verify,
+ )
+
+ @cached_property
+ def reset(self) -> ResetResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return ResetResourceWithRawResponse(self._recovery_code.reset)
+
+
+class AsyncRecoveryCodeResourceWithRawResponse:
+ def __init__(self, recovery_code: AsyncRecoveryCodeResource) -> None:
+ self._recovery_code = recovery_code
+
+ self.mark_backed_up = async_to_raw_response_wrapper(
+ recovery_code.mark_backed_up,
+ )
+ self.verify = async_to_raw_response_wrapper(
+ recovery_code.verify,
+ )
+
+ @cached_property
+ def reset(self) -> AsyncResetResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncResetResourceWithRawResponse(self._recovery_code.reset)
+
+
+class RecoveryCodeResourceWithStreamingResponse:
+ def __init__(self, recovery_code: RecoveryCodeResource) -> None:
+ self._recovery_code = recovery_code
+
+ self.mark_backed_up = to_streamed_response_wrapper(
+ recovery_code.mark_backed_up,
+ )
+ self.verify = to_streamed_response_wrapper(
+ recovery_code.verify,
+ )
+
+ @cached_property
+ def reset(self) -> ResetResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return ResetResourceWithStreamingResponse(self._recovery_code.reset)
+
+
+class AsyncRecoveryCodeResourceWithStreamingResponse:
+ def __init__(self, recovery_code: AsyncRecoveryCodeResource) -> None:
+ self._recovery_code = recovery_code
+
+ self.mark_backed_up = async_to_streamed_response_wrapper(
+ recovery_code.mark_backed_up,
+ )
+ self.verify = async_to_streamed_response_wrapper(
+ recovery_code.verify,
+ )
+
+ @cached_property
+ def reset(self) -> AsyncResetResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncResetResourceWithStreamingResponse(self._recovery_code.reset)
diff --git a/src/beeper_desktop_api/resources/app/e2ee/recovery_code/reset.py b/src/beeper_desktop_api/resources/app/e2ee/recovery_code/reset.py
new file mode 100644
index 0000000..63a7fa0
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/e2ee/recovery_code/reset.py
@@ -0,0 +1,252 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ....._utils import 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.app.e2ee.recovery_code import reset_create_params, reset_confirm_params
+from .....types.app.e2ee.recovery_code.reset_create_response import ResetCreateResponse
+from .....types.app.e2ee.recovery_code.reset_confirm_response import ResetConfirmResponse
+
+__all__ = ["ResetResource", "AsyncResetResource"]
+
+
+class ResetResource(SyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def with_raw_response(self) -> ResetResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return ResetResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ResetResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return ResetResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ recovery_code: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ResetCreateResponse:
+ """
+ Create a new recovery key when the user cannot use the existing one.
+
+ Args:
+ recovery_code: Existing recovery key, if the user has it.
+
+ 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(
+ "/v1/app/e2ee/recovery-code/reset",
+ body=maybe_transform({"recovery_code": recovery_code}, reset_create_params.ResetCreateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ResetCreateResponse,
+ )
+
+ def confirm(
+ self,
+ *,
+ recovery_code: 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,
+ ) -> ResetConfirmResponse:
+ """
+ Confirm that the new recovery key should be used for this account.
+
+ Args:
+ recovery_code: New recovery key returned by the reset step.
+
+ 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(
+ "/v1/app/e2ee/recovery-code/reset/confirm",
+ body=maybe_transform({"recovery_code": recovery_code}, reset_confirm_params.ResetConfirmParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ResetConfirmResponse,
+ )
+
+
+class AsyncResetResource(AsyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncResetResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncResetResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncResetResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncResetResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ recovery_code: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ResetCreateResponse:
+ """
+ Create a new recovery key when the user cannot use the existing one.
+
+ Args:
+ recovery_code: Existing recovery key, if the user has it.
+
+ 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(
+ "/v1/app/e2ee/recovery-code/reset",
+ body=await async_maybe_transform({"recovery_code": recovery_code}, reset_create_params.ResetCreateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ResetCreateResponse,
+ )
+
+ async def confirm(
+ self,
+ *,
+ recovery_code: 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,
+ ) -> ResetConfirmResponse:
+ """
+ Confirm that the new recovery key should be used for this account.
+
+ Args:
+ recovery_code: New recovery key returned by the reset step.
+
+ 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(
+ "/v1/app/e2ee/recovery-code/reset/confirm",
+ body=await async_maybe_transform({"recovery_code": recovery_code}, reset_confirm_params.ResetConfirmParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ResetConfirmResponse,
+ )
+
+
+class ResetResourceWithRawResponse:
+ def __init__(self, reset: ResetResource) -> None:
+ self._reset = reset
+
+ self.create = to_raw_response_wrapper(
+ reset.create,
+ )
+ self.confirm = to_raw_response_wrapper(
+ reset.confirm,
+ )
+
+
+class AsyncResetResourceWithRawResponse:
+ def __init__(self, reset: AsyncResetResource) -> None:
+ self._reset = reset
+
+ self.create = async_to_raw_response_wrapper(
+ reset.create,
+ )
+ self.confirm = async_to_raw_response_wrapper(
+ reset.confirm,
+ )
+
+
+class ResetResourceWithStreamingResponse:
+ def __init__(self, reset: ResetResource) -> None:
+ self._reset = reset
+
+ self.create = to_streamed_response_wrapper(
+ reset.create,
+ )
+ self.confirm = to_streamed_response_wrapper(
+ reset.confirm,
+ )
+
+
+class AsyncResetResourceWithStreamingResponse:
+ def __init__(self, reset: AsyncResetResource) -> None:
+ self._reset = reset
+
+ self.create = async_to_streamed_response_wrapper(
+ reset.create,
+ )
+ self.confirm = async_to_streamed_response_wrapper(
+ reset.confirm,
+ )
diff --git a/src/beeper_desktop_api/resources/app/e2ee/verification/__init__.py b/src/beeper_desktop_api/resources/app/e2ee/verification/__init__.py
new file mode 100644
index 0000000..920dcd8
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/e2ee/verification/__init__.py
@@ -0,0 +1,47 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .qr import (
+ QrResource,
+ AsyncQrResource,
+ QrResourceWithRawResponse,
+ AsyncQrResourceWithRawResponse,
+ QrResourceWithStreamingResponse,
+ AsyncQrResourceWithStreamingResponse,
+)
+from .sas import (
+ SasResource,
+ AsyncSasResource,
+ SasResourceWithRawResponse,
+ AsyncSasResourceWithRawResponse,
+ SasResourceWithStreamingResponse,
+ AsyncSasResourceWithStreamingResponse,
+)
+from .verification import (
+ VerificationResource,
+ AsyncVerificationResource,
+ VerificationResourceWithRawResponse,
+ AsyncVerificationResourceWithRawResponse,
+ VerificationResourceWithStreamingResponse,
+ AsyncVerificationResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "QrResource",
+ "AsyncQrResource",
+ "QrResourceWithRawResponse",
+ "AsyncQrResourceWithRawResponse",
+ "QrResourceWithStreamingResponse",
+ "AsyncQrResourceWithStreamingResponse",
+ "SasResource",
+ "AsyncSasResource",
+ "SasResourceWithRawResponse",
+ "AsyncSasResourceWithRawResponse",
+ "SasResourceWithStreamingResponse",
+ "AsyncSasResourceWithStreamingResponse",
+ "VerificationResource",
+ "AsyncVerificationResource",
+ "VerificationResourceWithRawResponse",
+ "AsyncVerificationResourceWithRawResponse",
+ "VerificationResourceWithStreamingResponse",
+ "AsyncVerificationResourceWithStreamingResponse",
+]
diff --git a/src/beeper_desktop_api/resources/app/e2ee/verification/qr.py b/src/beeper_desktop_api/resources/app/e2ee/verification/qr.py
new file mode 100644
index 0000000..a501c23
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/e2ee/verification/qr.py
@@ -0,0 +1,258 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ....._types import Body, Query, Headers, NotGiven, not_given
+from ....._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 ....._base_client import make_request_options
+from .....types.app.e2ee.verification import qr_scan_params
+from .....types.app.e2ee.verification.qr_scan_response import QrScanResponse
+from .....types.app.e2ee.verification.qr_confirm_scanned_response import QrConfirmScannedResponse
+
+__all__ = ["QrResource", "AsyncQrResource"]
+
+
+class QrResource(SyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def with_raw_response(self) -> QrResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return QrResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> QrResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return QrResourceWithStreamingResponse(self)
+
+ def confirm_scanned(
+ self,
+ verification_id: 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,
+ ) -> QrConfirmScannedResponse:
+ """
+ Confirm that another device scanned this device QR code.
+
+ Args:
+ verification_id: Verification ID.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return self._post(
+ path_template(
+ "/v1/app/e2ee/verification/{verification_id}/qr/confirm-scanned", verification_id=verification_id
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=QrConfirmScannedResponse,
+ )
+
+ def scan(
+ self,
+ *,
+ data: 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,
+ ) -> QrScanResponse:
+ """
+ Submit the QR code scanned from another signed-in device.
+
+ Args:
+ data: QR code payload scanned from the other device.
+
+ 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(
+ "/v1/app/e2ee/verification/qr/scan",
+ body=maybe_transform({"data": data}, qr_scan_params.QrScanParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=QrScanResponse,
+ )
+
+
+class AsyncQrResource(AsyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncQrResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncQrResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncQrResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncQrResourceWithStreamingResponse(self)
+
+ async def confirm_scanned(
+ self,
+ verification_id: 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,
+ ) -> QrConfirmScannedResponse:
+ """
+ Confirm that another device scanned this device QR code.
+
+ Args:
+ verification_id: Verification ID.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return await self._post(
+ path_template(
+ "/v1/app/e2ee/verification/{verification_id}/qr/confirm-scanned", verification_id=verification_id
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=QrConfirmScannedResponse,
+ )
+
+ async def scan(
+ self,
+ *,
+ data: 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,
+ ) -> QrScanResponse:
+ """
+ Submit the QR code scanned from another signed-in device.
+
+ Args:
+ data: QR code payload scanned from the other device.
+
+ 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(
+ "/v1/app/e2ee/verification/qr/scan",
+ body=await async_maybe_transform({"data": data}, qr_scan_params.QrScanParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=QrScanResponse,
+ )
+
+
+class QrResourceWithRawResponse:
+ def __init__(self, qr: QrResource) -> None:
+ self._qr = qr
+
+ self.confirm_scanned = to_raw_response_wrapper(
+ qr.confirm_scanned,
+ )
+ self.scan = to_raw_response_wrapper(
+ qr.scan,
+ )
+
+
+class AsyncQrResourceWithRawResponse:
+ def __init__(self, qr: AsyncQrResource) -> None:
+ self._qr = qr
+
+ self.confirm_scanned = async_to_raw_response_wrapper(
+ qr.confirm_scanned,
+ )
+ self.scan = async_to_raw_response_wrapper(
+ qr.scan,
+ )
+
+
+class QrResourceWithStreamingResponse:
+ def __init__(self, qr: QrResource) -> None:
+ self._qr = qr
+
+ self.confirm_scanned = to_streamed_response_wrapper(
+ qr.confirm_scanned,
+ )
+ self.scan = to_streamed_response_wrapper(
+ qr.scan,
+ )
+
+
+class AsyncQrResourceWithStreamingResponse:
+ def __init__(self, qr: AsyncQrResource) -> None:
+ self._qr = qr
+
+ self.confirm_scanned = async_to_streamed_response_wrapper(
+ qr.confirm_scanned,
+ )
+ self.scan = async_to_streamed_response_wrapper(
+ qr.scan,
+ )
diff --git a/src/beeper_desktop_api/resources/app/e2ee/verification/sas.py b/src/beeper_desktop_api/resources/app/e2ee/verification/sas.py
new file mode 100644
index 0000000..f72cd16
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/e2ee/verification/sas.py
@@ -0,0 +1,255 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ....._types import Body, Query, Headers, NotGiven, not_given
+from ....._utils import path_template
+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.app.e2ee.verification.sa_start_response import SaStartResponse
+from .....types.app.e2ee.verification.sa_confirm_response import SaConfirmResponse
+
+__all__ = ["SasResource", "AsyncSasResource"]
+
+
+class SasResource(SyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def with_raw_response(self) -> SasResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return SasResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> SasResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return SasResourceWithStreamingResponse(self)
+
+ def confirm(
+ self,
+ verification_id: 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,
+ ) -> SaConfirmResponse:
+ """
+ Confirm that the emoji or number sequence matches on both devices.
+
+ Args:
+ verification_id: Verification ID.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return self._post(
+ path_template("/v1/app/e2ee/verification/{verification_id}/sas/confirm", verification_id=verification_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SaConfirmResponse,
+ )
+
+ def start(
+ self,
+ verification_id: 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,
+ ) -> SaStartResponse:
+ """
+ Start emoji comparison for device verification.
+
+ Args:
+ verification_id: Verification ID.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return self._post(
+ path_template("/v1/app/e2ee/verification/{verification_id}/sas/start", verification_id=verification_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SaStartResponse,
+ )
+
+
+class AsyncSasResource(AsyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncSasResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncSasResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncSasResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncSasResourceWithStreamingResponse(self)
+
+ async def confirm(
+ self,
+ verification_id: 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,
+ ) -> SaConfirmResponse:
+ """
+ Confirm that the emoji or number sequence matches on both devices.
+
+ Args:
+ verification_id: Verification ID.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return await self._post(
+ path_template("/v1/app/e2ee/verification/{verification_id}/sas/confirm", verification_id=verification_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SaConfirmResponse,
+ )
+
+ async def start(
+ self,
+ verification_id: 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,
+ ) -> SaStartResponse:
+ """
+ Start emoji comparison for device verification.
+
+ Args:
+ verification_id: Verification ID.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return await self._post(
+ path_template("/v1/app/e2ee/verification/{verification_id}/sas/start", verification_id=verification_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=SaStartResponse,
+ )
+
+
+class SasResourceWithRawResponse:
+ def __init__(self, sas: SasResource) -> None:
+ self._sas = sas
+
+ self.confirm = to_raw_response_wrapper(
+ sas.confirm,
+ )
+ self.start = to_raw_response_wrapper(
+ sas.start,
+ )
+
+
+class AsyncSasResourceWithRawResponse:
+ def __init__(self, sas: AsyncSasResource) -> None:
+ self._sas = sas
+
+ self.confirm = async_to_raw_response_wrapper(
+ sas.confirm,
+ )
+ self.start = async_to_raw_response_wrapper(
+ sas.start,
+ )
+
+
+class SasResourceWithStreamingResponse:
+ def __init__(self, sas: SasResource) -> None:
+ self._sas = sas
+
+ self.confirm = to_streamed_response_wrapper(
+ sas.confirm,
+ )
+ self.start = to_streamed_response_wrapper(
+ sas.start,
+ )
+
+
+class AsyncSasResourceWithStreamingResponse:
+ def __init__(self, sas: AsyncSasResource) -> None:
+ self._sas = sas
+
+ self.confirm = async_to_streamed_response_wrapper(
+ sas.confirm,
+ )
+ self.start = async_to_streamed_response_wrapper(
+ sas.start,
+ )
diff --git a/src/beeper_desktop_api/resources/app/e2ee/verification/verification.py b/src/beeper_desktop_api/resources/app/e2ee/verification/verification.py
new file mode 100644
index 0000000..589e07f
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/e2ee/verification/verification.py
@@ -0,0 +1,439 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from .qr import (
+ QrResource,
+ AsyncQrResource,
+ QrResourceWithRawResponse,
+ AsyncQrResourceWithRawResponse,
+ QrResourceWithStreamingResponse,
+ AsyncQrResourceWithStreamingResponse,
+)
+from .sas import (
+ SasResource,
+ AsyncSasResource,
+ SasResourceWithRawResponse,
+ AsyncSasResourceWithRawResponse,
+ SasResourceWithStreamingResponse,
+ AsyncSasResourceWithStreamingResponse,
+)
+from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ....._utils import path_template, maybe_transform, async_maybe_transform
+from ....._compat import cached_property
+from ....._resource import SyncAPIResource, AsyncAPIResource
+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.app.e2ee import verification_cancel_params, verification_create_params
+from .....types.app.e2ee.verification_accept_response import VerificationAcceptResponse
+from .....types.app.e2ee.verification_cancel_response import VerificationCancelResponse
+from .....types.app.e2ee.verification_create_response import VerificationCreateResponse
+
+__all__ = ["VerificationResource", "AsyncVerificationResource"]
+
+
+class VerificationResource(SyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def qr(self) -> QrResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return QrResource(self._client)
+
+ @cached_property
+ def sas(self) -> SasResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return SasResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> VerificationResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return VerificationResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> VerificationResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return VerificationResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ user_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> VerificationCreateResponse:
+ """
+ Start verifying this device from another signed-in device.
+
+ Args:
+ user_id: User ID to verify. Defaults to the signed-in user.
+
+ 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(
+ "/v1/app/e2ee/verification",
+ body=maybe_transform({"user_id": user_id}, verification_create_params.VerificationCreateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationCreateResponse,
+ )
+
+ def accept(
+ self,
+ verification_id: 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,
+ ) -> VerificationAcceptResponse:
+ """
+ Accept an incoming device verification request.
+
+ Args:
+ verification_id: Verification ID.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return self._post(
+ path_template("/v1/app/e2ee/verification/{verification_id}/accept", verification_id=verification_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationAcceptResponse,
+ )
+
+ def cancel(
+ self,
+ verification_id: str,
+ *,
+ code: str | Omit = omit,
+ reason: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> VerificationCancelResponse:
+ """
+ Cancel an active device verification request.
+
+ Args:
+ verification_id: Verification ID.
+
+ code: Optional cancellation code.
+
+ reason: Optional user-facing cancellation reason.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return self._post(
+ path_template("/v1/app/e2ee/verification/{verification_id}/cancel", verification_id=verification_id),
+ body=maybe_transform(
+ {
+ "code": code,
+ "reason": reason,
+ },
+ verification_cancel_params.VerificationCancelParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationCancelResponse,
+ )
+
+
+class AsyncVerificationResource(AsyncAPIResource):
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+
+ @cached_property
+ def qr(self) -> AsyncQrResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncQrResource(self._client)
+
+ @cached_property
+ def sas(self) -> AsyncSasResource:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncSasResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncVerificationResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncVerificationResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncVerificationResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncVerificationResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ user_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> VerificationCreateResponse:
+ """
+ Start verifying this device from another signed-in device.
+
+ Args:
+ user_id: User ID to verify. Defaults to the signed-in user.
+
+ 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(
+ "/v1/app/e2ee/verification",
+ body=await async_maybe_transform({"user_id": user_id}, verification_create_params.VerificationCreateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationCreateResponse,
+ )
+
+ async def accept(
+ self,
+ verification_id: 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,
+ ) -> VerificationAcceptResponse:
+ """
+ Accept an incoming device verification request.
+
+ Args:
+ verification_id: Verification ID.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return await self._post(
+ path_template("/v1/app/e2ee/verification/{verification_id}/accept", verification_id=verification_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationAcceptResponse,
+ )
+
+ async def cancel(
+ self,
+ verification_id: str,
+ *,
+ code: str | Omit = omit,
+ reason: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> VerificationCancelResponse:
+ """
+ Cancel an active device verification request.
+
+ Args:
+ verification_id: Verification ID.
+
+ code: Optional cancellation code.
+
+ reason: Optional user-facing cancellation reason.
+
+ 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 verification_id:
+ raise ValueError(f"Expected a non-empty value for `verification_id` but received {verification_id!r}")
+ return await self._post(
+ path_template("/v1/app/e2ee/verification/{verification_id}/cancel", verification_id=verification_id),
+ body=await async_maybe_transform(
+ {
+ "code": code,
+ "reason": reason,
+ },
+ verification_cancel_params.VerificationCancelParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=VerificationCancelResponse,
+ )
+
+
+class VerificationResourceWithRawResponse:
+ def __init__(self, verification: VerificationResource) -> None:
+ self._verification = verification
+
+ self.create = to_raw_response_wrapper(
+ verification.create,
+ )
+ self.accept = to_raw_response_wrapper(
+ verification.accept,
+ )
+ self.cancel = to_raw_response_wrapper(
+ verification.cancel,
+ )
+
+ @cached_property
+ def qr(self) -> QrResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return QrResourceWithRawResponse(self._verification.qr)
+
+ @cached_property
+ def sas(self) -> SasResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return SasResourceWithRawResponse(self._verification.sas)
+
+
+class AsyncVerificationResourceWithRawResponse:
+ def __init__(self, verification: AsyncVerificationResource) -> None:
+ self._verification = verification
+
+ self.create = async_to_raw_response_wrapper(
+ verification.create,
+ )
+ self.accept = async_to_raw_response_wrapper(
+ verification.accept,
+ )
+ self.cancel = async_to_raw_response_wrapper(
+ verification.cancel,
+ )
+
+ @cached_property
+ def qr(self) -> AsyncQrResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncQrResourceWithRawResponse(self._verification.qr)
+
+ @cached_property
+ def sas(self) -> AsyncSasResourceWithRawResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncSasResourceWithRawResponse(self._verification.sas)
+
+
+class VerificationResourceWithStreamingResponse:
+ def __init__(self, verification: VerificationResource) -> None:
+ self._verification = verification
+
+ self.create = to_streamed_response_wrapper(
+ verification.create,
+ )
+ self.accept = to_streamed_response_wrapper(
+ verification.accept,
+ )
+ self.cancel = to_streamed_response_wrapper(
+ verification.cancel,
+ )
+
+ @cached_property
+ def qr(self) -> QrResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return QrResourceWithStreamingResponse(self._verification.qr)
+
+ @cached_property
+ def sas(self) -> SasResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return SasResourceWithStreamingResponse(self._verification.sas)
+
+
+class AsyncVerificationResourceWithStreamingResponse:
+ def __init__(self, verification: AsyncVerificationResource) -> None:
+ self._verification = verification
+
+ self.create = async_to_streamed_response_wrapper(
+ verification.create,
+ )
+ self.accept = async_to_streamed_response_wrapper(
+ verification.accept,
+ )
+ self.cancel = async_to_streamed_response_wrapper(
+ verification.cancel,
+ )
+
+ @cached_property
+ def qr(self) -> AsyncQrResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncQrResourceWithStreamingResponse(self._verification.qr)
+
+ @cached_property
+ def sas(self) -> AsyncSasResourceWithStreamingResponse:
+ """First-party sign-in and encrypted messaging setup for Beeper Desktop."""
+ return AsyncSasResourceWithStreamingResponse(self._verification.sas)
diff --git a/src/beeper_desktop_api/resources/app/login.py b/src/beeper_desktop_api/resources/app/login.py
new file mode 100644
index 0000000..e67ff28
--- /dev/null
+++ b/src/beeper_desktop_api/resources/app/login.py
@@ -0,0 +1,508 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Any, cast
+from typing_extensions import Literal
+
+import httpx
+
+from ..._types import Body, Query, Headers, NotGiven, not_given
+from ..._utils import 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 ...types.app import login_email_params, login_register_params, login_response_params
+from ..._base_client import make_request_options
+from ...types.app.login_start_response import LoginStartResponse
+from ...types.app.login_register_response import LoginRegisterResponse
+from ...types.app.login_response_response import LoginResponseResponse
+
+__all__ = ["LoginResource", "AsyncLoginResource"]
+
+
+class LoginResource(SyncAPIResource):
+ """Complete first-party Beeper app login"""
+
+ @cached_property
+ def with_raw_response(self) -> LoginResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return LoginResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> LoginResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return LoginResourceWithStreamingResponse(self)
+
+ def email(
+ self,
+ *,
+ email: str,
+ request: 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,
+ ) -> object:
+ """
+ Send a sign-in code to the user email address.
+
+ Args:
+ email: Email address to send the sign-in code to.
+
+ request: Login request ID returned by the start step.
+
+ 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(
+ "/v1/app/login/email",
+ body=maybe_transform(
+ {
+ "email": email,
+ "request": request,
+ },
+ login_email_params.LoginEmailParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={},
+ ),
+ cast_to=object,
+ )
+
+ def register(
+ self,
+ *,
+ accept_terms: Literal[True],
+ lead_token: str,
+ request: str,
+ username: 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,
+ ) -> LoginRegisterResponse:
+ """
+ Create a Beeper account after the user chooses a username and accepts the Terms
+ of Use.
+
+ Args:
+ accept_terms: Confirms that the user accepted the Terms of Use and acknowledged the Privacy
+ Policy.
+
+ lead_token: Registration token returned by Beeper.
+
+ request: Login request ID returned by the start step.
+
+ username: Username selected by the user.
+
+ 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(
+ "/v1/app/login/register",
+ body=maybe_transform(
+ {
+ "accept_terms": accept_terms,
+ "lead_token": lead_token,
+ "request": request,
+ "username": username,
+ },
+ login_register_params.LoginRegisterParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={},
+ ),
+ cast_to=LoginRegisterResponse,
+ )
+
+ def response(
+ self,
+ *,
+ request: str,
+ response: 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,
+ ) -> LoginResponseResponse:
+ """Finish sign-in with the code sent to the user email address.
+
+ If the user needs a
+ new account, the response includes account creation copy and username
+ suggestions.
+
+ Args:
+ request: Login request ID returned by the start step.
+
+ response: Sign-in code from the user email.
+
+ 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 cast(
+ LoginResponseResponse,
+ self._post(
+ "/v1/app/login/response",
+ body=maybe_transform(
+ {
+ "request": request,
+ "response": response,
+ },
+ login_response_params.LoginResponseParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={},
+ ),
+ cast_to=cast(
+ Any, LoginResponseResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def start(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> LoginStartResponse:
+ """Start a first-party Beeper Desktop sign-in session."""
+ return self._post(
+ "/v1/app/login/start",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={},
+ ),
+ cast_to=LoginStartResponse,
+ )
+
+
+class AsyncLoginResource(AsyncAPIResource):
+ """Complete first-party Beeper app login"""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncLoginResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncLoginResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncLoginResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncLoginResourceWithStreamingResponse(self)
+
+ async def email(
+ self,
+ *,
+ email: str,
+ request: 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,
+ ) -> object:
+ """
+ Send a sign-in code to the user email address.
+
+ Args:
+ email: Email address to send the sign-in code to.
+
+ request: Login request ID returned by the start step.
+
+ 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(
+ "/v1/app/login/email",
+ body=await async_maybe_transform(
+ {
+ "email": email,
+ "request": request,
+ },
+ login_email_params.LoginEmailParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={},
+ ),
+ cast_to=object,
+ )
+
+ async def register(
+ self,
+ *,
+ accept_terms: Literal[True],
+ lead_token: str,
+ request: str,
+ username: 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,
+ ) -> LoginRegisterResponse:
+ """
+ Create a Beeper account after the user chooses a username and accepts the Terms
+ of Use.
+
+ Args:
+ accept_terms: Confirms that the user accepted the Terms of Use and acknowledged the Privacy
+ Policy.
+
+ lead_token: Registration token returned by Beeper.
+
+ request: Login request ID returned by the start step.
+
+ username: Username selected by the user.
+
+ 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(
+ "/v1/app/login/register",
+ body=await async_maybe_transform(
+ {
+ "accept_terms": accept_terms,
+ "lead_token": lead_token,
+ "request": request,
+ "username": username,
+ },
+ login_register_params.LoginRegisterParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={},
+ ),
+ cast_to=LoginRegisterResponse,
+ )
+
+ async def response(
+ self,
+ *,
+ request: str,
+ response: 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,
+ ) -> LoginResponseResponse:
+ """Finish sign-in with the code sent to the user email address.
+
+ If the user needs a
+ new account, the response includes account creation copy and username
+ suggestions.
+
+ Args:
+ request: Login request ID returned by the start step.
+
+ response: Sign-in code from the user email.
+
+ 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 cast(
+ LoginResponseResponse,
+ await self._post(
+ "/v1/app/login/response",
+ body=await async_maybe_transform(
+ {
+ "request": request,
+ "response": response,
+ },
+ login_response_params.LoginResponseParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={},
+ ),
+ cast_to=cast(
+ Any, LoginResponseResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ async def start(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> LoginStartResponse:
+ """Start a first-party Beeper Desktop sign-in session."""
+ return await self._post(
+ "/v1/app/login/start",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ security={},
+ ),
+ cast_to=LoginStartResponse,
+ )
+
+
+class LoginResourceWithRawResponse:
+ def __init__(self, login: LoginResource) -> None:
+ self._login = login
+
+ self.email = to_raw_response_wrapper(
+ login.email,
+ )
+ self.register = to_raw_response_wrapper(
+ login.register,
+ )
+ self.response = to_raw_response_wrapper(
+ login.response,
+ )
+ self.start = to_raw_response_wrapper(
+ login.start,
+ )
+
+
+class AsyncLoginResourceWithRawResponse:
+ def __init__(self, login: AsyncLoginResource) -> None:
+ self._login = login
+
+ self.email = async_to_raw_response_wrapper(
+ login.email,
+ )
+ self.register = async_to_raw_response_wrapper(
+ login.register,
+ )
+ self.response = async_to_raw_response_wrapper(
+ login.response,
+ )
+ self.start = async_to_raw_response_wrapper(
+ login.start,
+ )
+
+
+class LoginResourceWithStreamingResponse:
+ def __init__(self, login: LoginResource) -> None:
+ self._login = login
+
+ self.email = to_streamed_response_wrapper(
+ login.email,
+ )
+ self.register = to_streamed_response_wrapper(
+ login.register,
+ )
+ self.response = to_streamed_response_wrapper(
+ login.response,
+ )
+ self.start = to_streamed_response_wrapper(
+ login.start,
+ )
+
+
+class AsyncLoginResourceWithStreamingResponse:
+ def __init__(self, login: AsyncLoginResource) -> None:
+ self._login = login
+
+ self.email = async_to_streamed_response_wrapper(
+ login.email,
+ )
+ self.register = async_to_streamed_response_wrapper(
+ login.register,
+ )
+ self.response = async_to_streamed_response_wrapper(
+ login.response,
+ )
+ self.start = async_to_streamed_response_wrapper(
+ login.start,
+ )
diff --git a/src/beeper_desktop_api/resources/bridges.py b/src/beeper_desktop_api/resources/bridges.py
new file mode 100644
index 0000000..1d9e25a
--- /dev/null
+++ b/src/beeper_desktop_api/resources/bridges.py
@@ -0,0 +1,145 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from .._types import Body, Query, Headers, NotGiven, not_given
+from .._compat import cached_property
+from .._resource import SyncAPIResource, AsyncAPIResource
+from .._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from .._base_client import make_request_options
+from ..types.bridge_list_response import BridgeListResponse
+
+__all__ = ["BridgesResource", "AsyncBridgesResource"]
+
+
+class BridgesResource(SyncAPIResource):
+ """Manage bridge-backed account types and account availability"""
+
+ @cached_property
+ def with_raw_response(self) -> BridgesResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return BridgesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> BridgesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return BridgesResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> BridgeListResponse:
+ """
+ List bridge-backed account types that can be shown in add-account flows, grouped
+ with connected accounts that use the same Account schema as GET /v1/accounts.
+ """
+ return self._get(
+ "/v1/bridges",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=BridgeListResponse,
+ )
+
+
+class AsyncBridgesResource(AsyncAPIResource):
+ """Manage bridge-backed account types and account availability"""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncBridgesResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncBridgesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncBridgesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncBridgesResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ *,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> BridgeListResponse:
+ """
+ List bridge-backed account types that can be shown in add-account flows, grouped
+ with connected accounts that use the same Account schema as GET /v1/accounts.
+ """
+ return await self._get(
+ "/v1/bridges",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=BridgeListResponse,
+ )
+
+
+class BridgesResourceWithRawResponse:
+ def __init__(self, bridges: BridgesResource) -> None:
+ self._bridges = bridges
+
+ self.list = to_raw_response_wrapper(
+ bridges.list,
+ )
+
+
+class AsyncBridgesResourceWithRawResponse:
+ def __init__(self, bridges: AsyncBridgesResource) -> None:
+ self._bridges = bridges
+
+ self.list = async_to_raw_response_wrapper(
+ bridges.list,
+ )
+
+
+class BridgesResourceWithStreamingResponse:
+ def __init__(self, bridges: BridgesResource) -> None:
+ self._bridges = bridges
+
+ self.list = to_streamed_response_wrapper(
+ bridges.list,
+ )
+
+
+class AsyncBridgesResourceWithStreamingResponse:
+ def __init__(self, bridges: AsyncBridgesResource) -> None:
+ self._bridges = bridges
+
+ self.list = async_to_streamed_response_wrapper(
+ bridges.list,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/__init__.py b/src/beeper_desktop_api/resources/matrix/__init__.py
new file mode 100644
index 0000000..7d5901f
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/__init__.py
@@ -0,0 +1,61 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .rooms import (
+ RoomsResource,
+ AsyncRoomsResource,
+ RoomsResourceWithRawResponse,
+ AsyncRoomsResourceWithRawResponse,
+ RoomsResourceWithStreamingResponse,
+ AsyncRoomsResourceWithStreamingResponse,
+)
+from .users import (
+ UsersResource,
+ AsyncUsersResource,
+ UsersResourceWithRawResponse,
+ AsyncUsersResourceWithRawResponse,
+ UsersResourceWithStreamingResponse,
+ AsyncUsersResourceWithStreamingResponse,
+)
+from .matrix import (
+ MatrixResource,
+ AsyncMatrixResource,
+ MatrixResourceWithRawResponse,
+ AsyncMatrixResourceWithRawResponse,
+ MatrixResourceWithStreamingResponse,
+ AsyncMatrixResourceWithStreamingResponse,
+)
+from .bridges import (
+ BridgesResource,
+ AsyncBridgesResource,
+ BridgesResourceWithRawResponse,
+ AsyncBridgesResourceWithRawResponse,
+ BridgesResourceWithStreamingResponse,
+ AsyncBridgesResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "UsersResource",
+ "AsyncUsersResource",
+ "UsersResourceWithRawResponse",
+ "AsyncUsersResourceWithRawResponse",
+ "UsersResourceWithStreamingResponse",
+ "AsyncUsersResourceWithStreamingResponse",
+ "RoomsResource",
+ "AsyncRoomsResource",
+ "RoomsResourceWithRawResponse",
+ "AsyncRoomsResourceWithRawResponse",
+ "RoomsResourceWithStreamingResponse",
+ "AsyncRoomsResourceWithStreamingResponse",
+ "BridgesResource",
+ "AsyncBridgesResource",
+ "BridgesResourceWithRawResponse",
+ "AsyncBridgesResourceWithRawResponse",
+ "BridgesResourceWithStreamingResponse",
+ "AsyncBridgesResourceWithStreamingResponse",
+ "MatrixResource",
+ "AsyncMatrixResource",
+ "MatrixResourceWithRawResponse",
+ "AsyncMatrixResourceWithRawResponse",
+ "MatrixResourceWithStreamingResponse",
+ "AsyncMatrixResourceWithStreamingResponse",
+]
diff --git a/src/beeper_desktop_api/resources/matrix/bridges/__init__.py b/src/beeper_desktop_api/resources/matrix/bridges/__init__.py
new file mode 100644
index 0000000..e25079a
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/bridges/__init__.py
@@ -0,0 +1,89 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .auth import (
+ AuthResource,
+ AsyncAuthResource,
+ AuthResourceWithRawResponse,
+ AsyncAuthResourceWithRawResponse,
+ AuthResourceWithStreamingResponse,
+ AsyncAuthResourceWithStreamingResponse,
+)
+from .rooms import (
+ RoomsResource,
+ AsyncRoomsResource,
+ RoomsResourceWithRawResponse,
+ AsyncRoomsResourceWithRawResponse,
+ RoomsResourceWithStreamingResponse,
+ AsyncRoomsResourceWithStreamingResponse,
+)
+from .users import (
+ UsersResource,
+ AsyncUsersResource,
+ UsersResourceWithRawResponse,
+ AsyncUsersResourceWithRawResponse,
+ UsersResourceWithStreamingResponse,
+ AsyncUsersResourceWithStreamingResponse,
+)
+from .bridges import (
+ BridgesResource,
+ AsyncBridgesResource,
+ BridgesResourceWithRawResponse,
+ AsyncBridgesResourceWithRawResponse,
+ BridgesResourceWithStreamingResponse,
+ AsyncBridgesResourceWithStreamingResponse,
+)
+from .contacts import (
+ ContactsResource,
+ AsyncContactsResource,
+ ContactsResourceWithRawResponse,
+ AsyncContactsResourceWithRawResponse,
+ ContactsResourceWithStreamingResponse,
+ AsyncContactsResourceWithStreamingResponse,
+)
+from .capabilities import (
+ CapabilitiesResource,
+ AsyncCapabilitiesResource,
+ CapabilitiesResourceWithRawResponse,
+ AsyncCapabilitiesResourceWithRawResponse,
+ CapabilitiesResourceWithStreamingResponse,
+ AsyncCapabilitiesResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "AuthResource",
+ "AsyncAuthResource",
+ "AuthResourceWithRawResponse",
+ "AsyncAuthResourceWithRawResponse",
+ "AuthResourceWithStreamingResponse",
+ "AsyncAuthResourceWithStreamingResponse",
+ "ContactsResource",
+ "AsyncContactsResource",
+ "ContactsResourceWithRawResponse",
+ "AsyncContactsResourceWithRawResponse",
+ "ContactsResourceWithStreamingResponse",
+ "AsyncContactsResourceWithStreamingResponse",
+ "UsersResource",
+ "AsyncUsersResource",
+ "UsersResourceWithRawResponse",
+ "AsyncUsersResourceWithRawResponse",
+ "UsersResourceWithStreamingResponse",
+ "AsyncUsersResourceWithStreamingResponse",
+ "RoomsResource",
+ "AsyncRoomsResource",
+ "RoomsResourceWithRawResponse",
+ "AsyncRoomsResourceWithRawResponse",
+ "RoomsResourceWithStreamingResponse",
+ "AsyncRoomsResourceWithStreamingResponse",
+ "CapabilitiesResource",
+ "AsyncCapabilitiesResource",
+ "CapabilitiesResourceWithRawResponse",
+ "AsyncCapabilitiesResourceWithRawResponse",
+ "CapabilitiesResourceWithStreamingResponse",
+ "AsyncCapabilitiesResourceWithStreamingResponse",
+ "BridgesResource",
+ "AsyncBridgesResource",
+ "BridgesResourceWithRawResponse",
+ "AsyncBridgesResourceWithRawResponse",
+ "BridgesResourceWithStreamingResponse",
+ "AsyncBridgesResourceWithStreamingResponse",
+]
diff --git a/src/beeper_desktop_api/resources/matrix/bridges/auth.py b/src/beeper_desktop_api/resources/matrix/bridges/auth.py
new file mode 100644
index 0000000..b05ee19
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/bridges/auth.py
@@ -0,0 +1,951 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Any, Dict, cast
+
+import httpx
+
+from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ...._utils import path_template, maybe_transform, async_maybe_transform
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+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.matrix.bridges import auth_start_login_params, auth_submit_cookies_params, auth_submit_user_input_params
+from ....types.matrix.bridges.auth_whoami_response import AuthWhoamiResponse
+from ....types.matrix.bridges.auth_list_flows_response import AuthListFlowsResponse
+from ....types.matrix.bridges.auth_list_logins_response import AuthListLoginsResponse
+from ....types.matrix.bridges.auth_start_login_response import AuthStartLoginResponse
+from ....types.matrix.bridges.auth_wait_for_step_response import AuthWaitForStepResponse
+from ....types.matrix.bridges.auth_submit_cookies_response import AuthSubmitCookiesResponse
+from ....types.matrix.bridges.auth_submit_user_input_response import AuthSubmitUserInputResponse
+
+__all__ = ["AuthResource", "AsyncAuthResource"]
+
+
+class AuthResource(SyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> AuthResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AuthResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AuthResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AuthResourceWithStreamingResponse(self)
+
+ def list_flows(
+ self,
+ bridge_id: 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,
+ ) -> AuthListFlowsResponse:
+ """
+ Get the available login flows.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/flows",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AuthListFlowsResponse,
+ )
+
+ def list_logins(
+ self,
+ bridge_id: 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,
+ ) -> AuthListLoginsResponse:
+ """
+ Get the login IDs of the current user.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/logins",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AuthListLoginsResponse,
+ )
+
+ def logout(
+ self,
+ login_id: str,
+ *,
+ bridge_id: 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,
+ ) -> object:
+ """Log out of an existing login.
+
+ Args:
+ login_id: The unique ID of a login.
+
+ Defined by the network connector.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not login_id:
+ raise ValueError(f"Expected a non-empty value for `login_id` but received {login_id!r}")
+ return self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/logout/{login_id}",
+ bridge_id=bridge_id,
+ login_id=login_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ def start_login(
+ self,
+ flow_id: str,
+ *,
+ bridge_id: str,
+ login_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AuthStartLoginResponse:
+ """
+ This endpoint starts a new login process, which is used to log into the bridge.
+
+ The basic flow of the entire login, including calling this endpoint, is:
+
+ 1. Call `GET /v3/login/flows` to get the list of available flows. If there's
+ more than one flow, ask the user to pick which one they want to use.
+ 2. Call this endpoint with the chosen flow ID to start the login. The first
+ login step will be returned.
+ 3. Render the information provided in the step.
+ 4. Call the `/login/step/...` endpoint corresponding to the step type:
+ - For `user_input` and `cookies`, acquire the requested fields before calling
+ the endpoint.
+ - For `display_and_wait`, call the endpoint immediately (as there's nothing
+ to acquire on the client side).
+ 5. Handle the data returned by the login step endpoint:
+ - If an error is returned, the login has failed and must be restarted (from
+ either step 1 or step 2) if the user wants to try again.
+ - If step type `complete` is returned, the login finished successfully.
+ - Otherwise, go to step 3 with the new data.
+
+ Args:
+ login_id: An existing login ID to re-login as. If this is specified and the user logs into
+ a different account, the provided ID will be logged out.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not flow_id:
+ raise ValueError(f"Expected a non-empty value for `flow_id` but received {flow_id!r}")
+ return cast(
+ AuthStartLoginResponse,
+ self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/start/{flow_id}",
+ bridge_id=bridge_id,
+ flow_id=flow_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"login_id": login_id}, auth_start_login_params.AuthStartLoginParams),
+ ),
+ cast_to=cast(
+ Any, AuthStartLoginResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def submit_cookies(
+ self,
+ step_id: str,
+ *,
+ bridge_id: str,
+ login_process_id: str,
+ body: Dict[str, 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,
+ ) -> AuthSubmitCookiesResponse:
+ """
+ Submit extracted cookies in a login process.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not login_process_id:
+ raise ValueError(f"Expected a non-empty value for `login_process_id` but received {login_process_id!r}")
+ if not step_id:
+ raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}")
+ return cast(
+ AuthSubmitCookiesResponse,
+ self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/step/{login_process_id}/{step_id}/cookies",
+ bridge_id=bridge_id,
+ login_process_id=login_process_id,
+ step_id=step_id,
+ ),
+ body=maybe_transform(body, auth_submit_cookies_params.AuthSubmitCookiesParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AuthSubmitCookiesResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def submit_user_input(
+ self,
+ step_id: str,
+ *,
+ bridge_id: str,
+ login_process_id: str,
+ body: Dict[str, 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,
+ ) -> AuthSubmitUserInputResponse:
+ """
+ Submit user input in a login process.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not login_process_id:
+ raise ValueError(f"Expected a non-empty value for `login_process_id` but received {login_process_id!r}")
+ if not step_id:
+ raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}")
+ return cast(
+ AuthSubmitUserInputResponse,
+ self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/step/{login_process_id}/{step_id}/user_input",
+ bridge_id=bridge_id,
+ login_process_id=login_process_id,
+ step_id=step_id,
+ ),
+ body=maybe_transform(body, auth_submit_user_input_params.AuthSubmitUserInputParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AuthSubmitUserInputResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def wait_for_step(
+ self,
+ step_id: str,
+ *,
+ bridge_id: str,
+ login_process_id: 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,
+ ) -> AuthWaitForStepResponse:
+ """
+ Wait for the next step after displaying data to the user.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not login_process_id:
+ raise ValueError(f"Expected a non-empty value for `login_process_id` but received {login_process_id!r}")
+ if not step_id:
+ raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}")
+ return cast(
+ AuthWaitForStepResponse,
+ self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/step/{login_process_id}/{step_id}/display_and_wait",
+ bridge_id=bridge_id,
+ login_process_id=login_process_id,
+ step_id=step_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AuthWaitForStepResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ def whoami(
+ self,
+ bridge_id: 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,
+ ) -> AuthWhoamiResponse:
+ """
+ Get all info that is useful for presenting this bridge in a manager interface.
+
+ - Server details: remote network details, available login flows, homeserver
+ name, bridge bot user ID, command prefix
+ - User details: management room ID, list of logins with current state and info
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/whoami",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AuthWhoamiResponse,
+ )
+
+
+class AsyncAuthResource(AsyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncAuthResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncAuthResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAuthResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncAuthResourceWithStreamingResponse(self)
+
+ async def list_flows(
+ self,
+ bridge_id: 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,
+ ) -> AuthListFlowsResponse:
+ """
+ Get the available login flows.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return await self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/flows",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AuthListFlowsResponse,
+ )
+
+ async def list_logins(
+ self,
+ bridge_id: 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,
+ ) -> AuthListLoginsResponse:
+ """
+ Get the login IDs of the current user.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return await self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/logins",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AuthListLoginsResponse,
+ )
+
+ async def logout(
+ self,
+ login_id: str,
+ *,
+ bridge_id: 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,
+ ) -> object:
+ """Log out of an existing login.
+
+ Args:
+ login_id: The unique ID of a login.
+
+ Defined by the network connector.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not login_id:
+ raise ValueError(f"Expected a non-empty value for `login_id` but received {login_id!r}")
+ return await self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/logout/{login_id}",
+ bridge_id=bridge_id,
+ login_id=login_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ async def start_login(
+ self,
+ flow_id: str,
+ *,
+ bridge_id: str,
+ login_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> AuthStartLoginResponse:
+ """
+ This endpoint starts a new login process, which is used to log into the bridge.
+
+ The basic flow of the entire login, including calling this endpoint, is:
+
+ 1. Call `GET /v3/login/flows` to get the list of available flows. If there's
+ more than one flow, ask the user to pick which one they want to use.
+ 2. Call this endpoint with the chosen flow ID to start the login. The first
+ login step will be returned.
+ 3. Render the information provided in the step.
+ 4. Call the `/login/step/...` endpoint corresponding to the step type:
+ - For `user_input` and `cookies`, acquire the requested fields before calling
+ the endpoint.
+ - For `display_and_wait`, call the endpoint immediately (as there's nothing
+ to acquire on the client side).
+ 5. Handle the data returned by the login step endpoint:
+ - If an error is returned, the login has failed and must be restarted (from
+ either step 1 or step 2) if the user wants to try again.
+ - If step type `complete` is returned, the login finished successfully.
+ - Otherwise, go to step 3 with the new data.
+
+ Args:
+ login_id: An existing login ID to re-login as. If this is specified and the user logs into
+ a different account, the provided ID will be logged out.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not flow_id:
+ raise ValueError(f"Expected a non-empty value for `flow_id` but received {flow_id!r}")
+ return cast(
+ AuthStartLoginResponse,
+ await self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/start/{flow_id}",
+ bridge_id=bridge_id,
+ flow_id=flow_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"login_id": login_id}, auth_start_login_params.AuthStartLoginParams
+ ),
+ ),
+ cast_to=cast(
+ Any, AuthStartLoginResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ async def submit_cookies(
+ self,
+ step_id: str,
+ *,
+ bridge_id: str,
+ login_process_id: str,
+ body: Dict[str, 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,
+ ) -> AuthSubmitCookiesResponse:
+ """
+ Submit extracted cookies in a login process.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not login_process_id:
+ raise ValueError(f"Expected a non-empty value for `login_process_id` but received {login_process_id!r}")
+ if not step_id:
+ raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}")
+ return cast(
+ AuthSubmitCookiesResponse,
+ await self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/step/{login_process_id}/{step_id}/cookies",
+ bridge_id=bridge_id,
+ login_process_id=login_process_id,
+ step_id=step_id,
+ ),
+ body=await async_maybe_transform(body, auth_submit_cookies_params.AuthSubmitCookiesParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AuthSubmitCookiesResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ async def submit_user_input(
+ self,
+ step_id: str,
+ *,
+ bridge_id: str,
+ login_process_id: str,
+ body: Dict[str, 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,
+ ) -> AuthSubmitUserInputResponse:
+ """
+ Submit user input in a login process.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not login_process_id:
+ raise ValueError(f"Expected a non-empty value for `login_process_id` but received {login_process_id!r}")
+ if not step_id:
+ raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}")
+ return cast(
+ AuthSubmitUserInputResponse,
+ await self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/step/{login_process_id}/{step_id}/user_input",
+ bridge_id=bridge_id,
+ login_process_id=login_process_id,
+ step_id=step_id,
+ ),
+ body=await async_maybe_transform(body, auth_submit_user_input_params.AuthSubmitUserInputParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AuthSubmitUserInputResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ async def wait_for_step(
+ self,
+ step_id: str,
+ *,
+ bridge_id: str,
+ login_process_id: 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,
+ ) -> AuthWaitForStepResponse:
+ """
+ Wait for the next step after displaying data to the user.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not login_process_id:
+ raise ValueError(f"Expected a non-empty value for `login_process_id` but received {login_process_id!r}")
+ if not step_id:
+ raise ValueError(f"Expected a non-empty value for `step_id` but received {step_id!r}")
+ return cast(
+ AuthWaitForStepResponse,
+ await self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/login/step/{login_process_id}/{step_id}/display_and_wait",
+ bridge_id=bridge_id,
+ login_process_id=login_process_id,
+ step_id=step_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=cast(
+ Any, AuthWaitForStepResponse
+ ), # Union types cannot be passed in as arguments in the type system
+ ),
+ )
+
+ async def whoami(
+ self,
+ bridge_id: 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,
+ ) -> AuthWhoamiResponse:
+ """
+ Get all info that is useful for presenting this bridge in a manager interface.
+
+ - Server details: remote network details, available login flows, homeserver
+ name, bridge bot user ID, command prefix
+ - User details: management room ID, list of logins with current state and info
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return await self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/whoami",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=AuthWhoamiResponse,
+ )
+
+
+class AuthResourceWithRawResponse:
+ def __init__(self, auth: AuthResource) -> None:
+ self._auth = auth
+
+ self.list_flows = to_raw_response_wrapper(
+ auth.list_flows,
+ )
+ self.list_logins = to_raw_response_wrapper(
+ auth.list_logins,
+ )
+ self.logout = to_raw_response_wrapper(
+ auth.logout,
+ )
+ self.start_login = to_raw_response_wrapper(
+ auth.start_login,
+ )
+ self.submit_cookies = to_raw_response_wrapper(
+ auth.submit_cookies,
+ )
+ self.submit_user_input = to_raw_response_wrapper(
+ auth.submit_user_input,
+ )
+ self.wait_for_step = to_raw_response_wrapper(
+ auth.wait_for_step,
+ )
+ self.whoami = to_raw_response_wrapper(
+ auth.whoami,
+ )
+
+
+class AsyncAuthResourceWithRawResponse:
+ def __init__(self, auth: AsyncAuthResource) -> None:
+ self._auth = auth
+
+ self.list_flows = async_to_raw_response_wrapper(
+ auth.list_flows,
+ )
+ self.list_logins = async_to_raw_response_wrapper(
+ auth.list_logins,
+ )
+ self.logout = async_to_raw_response_wrapper(
+ auth.logout,
+ )
+ self.start_login = async_to_raw_response_wrapper(
+ auth.start_login,
+ )
+ self.submit_cookies = async_to_raw_response_wrapper(
+ auth.submit_cookies,
+ )
+ self.submit_user_input = async_to_raw_response_wrapper(
+ auth.submit_user_input,
+ )
+ self.wait_for_step = async_to_raw_response_wrapper(
+ auth.wait_for_step,
+ )
+ self.whoami = async_to_raw_response_wrapper(
+ auth.whoami,
+ )
+
+
+class AuthResourceWithStreamingResponse:
+ def __init__(self, auth: AuthResource) -> None:
+ self._auth = auth
+
+ self.list_flows = to_streamed_response_wrapper(
+ auth.list_flows,
+ )
+ self.list_logins = to_streamed_response_wrapper(
+ auth.list_logins,
+ )
+ self.logout = to_streamed_response_wrapper(
+ auth.logout,
+ )
+ self.start_login = to_streamed_response_wrapper(
+ auth.start_login,
+ )
+ self.submit_cookies = to_streamed_response_wrapper(
+ auth.submit_cookies,
+ )
+ self.submit_user_input = to_streamed_response_wrapper(
+ auth.submit_user_input,
+ )
+ self.wait_for_step = to_streamed_response_wrapper(
+ auth.wait_for_step,
+ )
+ self.whoami = to_streamed_response_wrapper(
+ auth.whoami,
+ )
+
+
+class AsyncAuthResourceWithStreamingResponse:
+ def __init__(self, auth: AsyncAuthResource) -> None:
+ self._auth = auth
+
+ self.list_flows = async_to_streamed_response_wrapper(
+ auth.list_flows,
+ )
+ self.list_logins = async_to_streamed_response_wrapper(
+ auth.list_logins,
+ )
+ self.logout = async_to_streamed_response_wrapper(
+ auth.logout,
+ )
+ self.start_login = async_to_streamed_response_wrapper(
+ auth.start_login,
+ )
+ self.submit_cookies = async_to_streamed_response_wrapper(
+ auth.submit_cookies,
+ )
+ self.submit_user_input = async_to_streamed_response_wrapper(
+ auth.submit_user_input,
+ )
+ self.wait_for_step = async_to_streamed_response_wrapper(
+ auth.wait_for_step,
+ )
+ self.whoami = async_to_streamed_response_wrapper(
+ auth.whoami,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/bridges/bridges.py b/src/beeper_desktop_api/resources/matrix/bridges/bridges.py
new file mode 100644
index 0000000..f2922c9
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/bridges/bridges.py
@@ -0,0 +1,264 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .auth import (
+ AuthResource,
+ AsyncAuthResource,
+ AuthResourceWithRawResponse,
+ AsyncAuthResourceWithRawResponse,
+ AuthResourceWithStreamingResponse,
+ AsyncAuthResourceWithStreamingResponse,
+)
+from .rooms import (
+ RoomsResource,
+ AsyncRoomsResource,
+ RoomsResourceWithRawResponse,
+ AsyncRoomsResourceWithRawResponse,
+ RoomsResourceWithStreamingResponse,
+ AsyncRoomsResourceWithStreamingResponse,
+)
+from .users import (
+ UsersResource,
+ AsyncUsersResource,
+ UsersResourceWithRawResponse,
+ AsyncUsersResourceWithRawResponse,
+ UsersResourceWithStreamingResponse,
+ AsyncUsersResourceWithStreamingResponse,
+)
+from .contacts import (
+ ContactsResource,
+ AsyncContactsResource,
+ ContactsResourceWithRawResponse,
+ AsyncContactsResourceWithRawResponse,
+ ContactsResourceWithStreamingResponse,
+ AsyncContactsResourceWithStreamingResponse,
+)
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+from .capabilities import (
+ CapabilitiesResource,
+ AsyncCapabilitiesResource,
+ CapabilitiesResourceWithRawResponse,
+ AsyncCapabilitiesResourceWithRawResponse,
+ CapabilitiesResourceWithStreamingResponse,
+ AsyncCapabilitiesResourceWithStreamingResponse,
+)
+
+__all__ = ["BridgesResource", "AsyncBridgesResource"]
+
+
+class BridgesResource(SyncAPIResource):
+ """Matrix-compatible APIs for connected network bridges."""
+
+ @cached_property
+ def auth(self) -> AuthResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AuthResource(self._client)
+
+ @cached_property
+ def contacts(self) -> ContactsResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return ContactsResource(self._client)
+
+ @cached_property
+ def users(self) -> UsersResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return UsersResource(self._client)
+
+ @cached_property
+ def rooms(self) -> RoomsResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return RoomsResource(self._client)
+
+ @cached_property
+ def capabilities(self) -> CapabilitiesResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return CapabilitiesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> BridgesResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return BridgesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> BridgesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return BridgesResourceWithStreamingResponse(self)
+
+
+class AsyncBridgesResource(AsyncAPIResource):
+ """Matrix-compatible APIs for connected network bridges."""
+
+ @cached_property
+ def auth(self) -> AsyncAuthResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncAuthResource(self._client)
+
+ @cached_property
+ def contacts(self) -> AsyncContactsResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncContactsResource(self._client)
+
+ @cached_property
+ def users(self) -> AsyncUsersResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncUsersResource(self._client)
+
+ @cached_property
+ def rooms(self) -> AsyncRoomsResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncRoomsResource(self._client)
+
+ @cached_property
+ def capabilities(self) -> AsyncCapabilitiesResource:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncCapabilitiesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncBridgesResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncBridgesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncBridgesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncBridgesResourceWithStreamingResponse(self)
+
+
+class BridgesResourceWithRawResponse:
+ def __init__(self, bridges: BridgesResource) -> None:
+ self._bridges = bridges
+
+ @cached_property
+ def auth(self) -> AuthResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AuthResourceWithRawResponse(self._bridges.auth)
+
+ @cached_property
+ def contacts(self) -> ContactsResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return ContactsResourceWithRawResponse(self._bridges.contacts)
+
+ @cached_property
+ def users(self) -> UsersResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return UsersResourceWithRawResponse(self._bridges.users)
+
+ @cached_property
+ def rooms(self) -> RoomsResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return RoomsResourceWithRawResponse(self._bridges.rooms)
+
+ @cached_property
+ def capabilities(self) -> CapabilitiesResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return CapabilitiesResourceWithRawResponse(self._bridges.capabilities)
+
+
+class AsyncBridgesResourceWithRawResponse:
+ def __init__(self, bridges: AsyncBridgesResource) -> None:
+ self._bridges = bridges
+
+ @cached_property
+ def auth(self) -> AsyncAuthResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncAuthResourceWithRawResponse(self._bridges.auth)
+
+ @cached_property
+ def contacts(self) -> AsyncContactsResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncContactsResourceWithRawResponse(self._bridges.contacts)
+
+ @cached_property
+ def users(self) -> AsyncUsersResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncUsersResourceWithRawResponse(self._bridges.users)
+
+ @cached_property
+ def rooms(self) -> AsyncRoomsResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncRoomsResourceWithRawResponse(self._bridges.rooms)
+
+ @cached_property
+ def capabilities(self) -> AsyncCapabilitiesResourceWithRawResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncCapabilitiesResourceWithRawResponse(self._bridges.capabilities)
+
+
+class BridgesResourceWithStreamingResponse:
+ def __init__(self, bridges: BridgesResource) -> None:
+ self._bridges = bridges
+
+ @cached_property
+ def auth(self) -> AuthResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AuthResourceWithStreamingResponse(self._bridges.auth)
+
+ @cached_property
+ def contacts(self) -> ContactsResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return ContactsResourceWithStreamingResponse(self._bridges.contacts)
+
+ @cached_property
+ def users(self) -> UsersResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return UsersResourceWithStreamingResponse(self._bridges.users)
+
+ @cached_property
+ def rooms(self) -> RoomsResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return RoomsResourceWithStreamingResponse(self._bridges.rooms)
+
+ @cached_property
+ def capabilities(self) -> CapabilitiesResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return CapabilitiesResourceWithStreamingResponse(self._bridges.capabilities)
+
+
+class AsyncBridgesResourceWithStreamingResponse:
+ def __init__(self, bridges: AsyncBridgesResource) -> None:
+ self._bridges = bridges
+
+ @cached_property
+ def auth(self) -> AsyncAuthResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncAuthResourceWithStreamingResponse(self._bridges.auth)
+
+ @cached_property
+ def contacts(self) -> AsyncContactsResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncContactsResourceWithStreamingResponse(self._bridges.contacts)
+
+ @cached_property
+ def users(self) -> AsyncUsersResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncUsersResourceWithStreamingResponse(self._bridges.users)
+
+ @cached_property
+ def rooms(self) -> AsyncRoomsResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncRoomsResourceWithStreamingResponse(self._bridges.rooms)
+
+ @cached_property
+ def capabilities(self) -> AsyncCapabilitiesResourceWithStreamingResponse:
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+ return AsyncCapabilitiesResourceWithStreamingResponse(self._bridges.capabilities)
diff --git a/src/beeper_desktop_api/resources/matrix/bridges/capabilities.py b/src/beeper_desktop_api/resources/matrix/bridges/capabilities.py
new file mode 100644
index 0000000..48338bc
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/bridges/capabilities.py
@@ -0,0 +1,174 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Query, Headers, NotGiven, not_given
+from ...._utils import path_template
+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.matrix.bridges.capability_retrieve_response import CapabilityRetrieveResponse
+
+__all__ = ["CapabilitiesResource", "AsyncCapabilitiesResource"]
+
+
+class CapabilitiesResource(SyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> CapabilitiesResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return CapabilitiesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> CapabilitiesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return CapabilitiesResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ bridge_id: 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,
+ ) -> CapabilityRetrieveResponse:
+ """
+ Get bridge capabilities
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/capabilities",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CapabilityRetrieveResponse,
+ )
+
+
+class AsyncCapabilitiesResource(AsyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncCapabilitiesResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncCapabilitiesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncCapabilitiesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncCapabilitiesResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ bridge_id: 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,
+ ) -> CapabilityRetrieveResponse:
+ """
+ Get bridge capabilities
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return await self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/capabilities",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=CapabilityRetrieveResponse,
+ )
+
+
+class CapabilitiesResourceWithRawResponse:
+ def __init__(self, capabilities: CapabilitiesResource) -> None:
+ self._capabilities = capabilities
+
+ self.retrieve = to_raw_response_wrapper(
+ capabilities.retrieve,
+ )
+
+
+class AsyncCapabilitiesResourceWithRawResponse:
+ def __init__(self, capabilities: AsyncCapabilitiesResource) -> None:
+ self._capabilities = capabilities
+
+ self.retrieve = async_to_raw_response_wrapper(
+ capabilities.retrieve,
+ )
+
+
+class CapabilitiesResourceWithStreamingResponse:
+ def __init__(self, capabilities: CapabilitiesResource) -> None:
+ self._capabilities = capabilities
+
+ self.retrieve = to_streamed_response_wrapper(
+ capabilities.retrieve,
+ )
+
+
+class AsyncCapabilitiesResourceWithStreamingResponse:
+ def __init__(self, capabilities: AsyncCapabilitiesResource) -> None:
+ self._capabilities = capabilities
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ capabilities.retrieve,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/bridges/contacts.py b/src/beeper_desktop_api/resources/matrix/bridges/contacts.py
new file mode 100644
index 0000000..1b7c10b
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/bridges/contacts.py
@@ -0,0 +1,189 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ...._utils import path_template, maybe_transform, async_maybe_transform
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+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.matrix.bridges import contact_list_params
+from ....types.matrix.bridges.contact_list_response import ContactListResponse
+
+__all__ = ["ContactsResource", "AsyncContactsResource"]
+
+
+class ContactsResource(SyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> ContactsResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return ContactsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ContactsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return ContactsResourceWithStreamingResponse(self)
+
+ def list(
+ self,
+ bridge_id: str,
+ *,
+ login_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ContactListResponse:
+ """
+ Get a list of contacts.
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/contacts",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"login_id": login_id}, contact_list_params.ContactListParams),
+ ),
+ cast_to=ContactListResponse,
+ )
+
+
+class AsyncContactsResource(AsyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncContactsResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncContactsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncContactsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncContactsResourceWithStreamingResponse(self)
+
+ async def list(
+ self,
+ bridge_id: str,
+ *,
+ login_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ContactListResponse:
+ """
+ Get a list of contacts.
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return await self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/contacts",
+ bridge_id=bridge_id,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"login_id": login_id}, contact_list_params.ContactListParams),
+ ),
+ cast_to=ContactListResponse,
+ )
+
+
+class ContactsResourceWithRawResponse:
+ def __init__(self, contacts: ContactsResource) -> None:
+ self._contacts = contacts
+
+ self.list = to_raw_response_wrapper(
+ contacts.list,
+ )
+
+
+class AsyncContactsResourceWithRawResponse:
+ def __init__(self, contacts: AsyncContactsResource) -> None:
+ self._contacts = contacts
+
+ self.list = async_to_raw_response_wrapper(
+ contacts.list,
+ )
+
+
+class ContactsResourceWithStreamingResponse:
+ def __init__(self, contacts: ContactsResource) -> None:
+ self._contacts = contacts
+
+ self.list = to_streamed_response_wrapper(
+ contacts.list,
+ )
+
+
+class AsyncContactsResourceWithStreamingResponse:
+ def __init__(self, contacts: AsyncContactsResource) -> None:
+ self._contacts = contacts
+
+ self.list = async_to_streamed_response_wrapper(
+ contacts.list,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/bridges/rooms.py b/src/beeper_desktop_api/resources/matrix/bridges/rooms.py
new file mode 100644
index 0000000..fcd9d9b
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/bridges/rooms.py
@@ -0,0 +1,386 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, 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 ...._base_client import make_request_options
+from ....types.matrix.bridges import room_create_dm_params, room_create_group_params
+from ....types.matrix.bridges.room_create_dm_response import RoomCreateDmResponse
+from ....types.matrix.bridges.room_create_group_response import RoomCreateGroupResponse
+
+__all__ = ["RoomsResource", "AsyncRoomsResource"]
+
+
+class RoomsResource(SyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> RoomsResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return RoomsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> RoomsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return RoomsResourceWithStreamingResponse(self)
+
+ def create_dm(
+ self,
+ identifier: str,
+ *,
+ bridge_id: str,
+ login_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RoomCreateDmResponse:
+ """
+ Create a direct chat with a user on the remote network.
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not identifier:
+ raise ValueError(f"Expected a non-empty value for `identifier` but received {identifier!r}")
+ return self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/create_dm/{identifier}",
+ bridge_id=bridge_id,
+ identifier=identifier,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"login_id": login_id}, room_create_dm_params.RoomCreateDmParams),
+ ),
+ cast_to=RoomCreateDmResponse,
+ )
+
+ def create_group(
+ self,
+ group_type: str,
+ *,
+ bridge_id: str,
+ login_id: str | Omit = omit,
+ avatar: room_create_group_params.Avatar | Omit = omit,
+ disappear: room_create_group_params.Disappear | Omit = omit,
+ name: room_create_group_params.Name | Omit = omit,
+ parent: object | Omit = omit,
+ participants: SequenceNotStr[str] | Omit = omit,
+ room_id: str | Omit = omit,
+ topic: room_create_group_params.Topic | Omit = omit,
+ type: str | Omit = omit,
+ username: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RoomCreateGroupResponse:
+ """
+ Create a group chat on the remote network.
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ avatar: The `m.room.avatar` event content for the room.
+
+ disappear: The `com.beeper.disappearing_timer` event content for the room.
+
+ name: The `m.room.name` event content for the room.
+
+ participants: The users to add to the group initially.
+
+ room_id: An existing Matrix room ID to bridge to. The other parameters must be already in
+ sync with the room state when using this parameter.
+
+ topic: The `m.room.topic` event content for the room.
+
+ type: The type of group to create.
+
+ username: The public username for the created group.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not group_type:
+ raise ValueError(f"Expected a non-empty value for `group_type` but received {group_type!r}")
+ return self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/create_group/{group_type}",
+ bridge_id=bridge_id,
+ group_type=group_type,
+ ),
+ body=maybe_transform(
+ {
+ "avatar": avatar,
+ "disappear": disappear,
+ "name": name,
+ "parent": parent,
+ "participants": participants,
+ "room_id": room_id,
+ "topic": topic,
+ "type": type,
+ "username": username,
+ },
+ room_create_group_params.RoomCreateGroupParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"login_id": login_id}, room_create_group_params.RoomCreateGroupParams),
+ ),
+ cast_to=RoomCreateGroupResponse,
+ )
+
+
+class AsyncRoomsResource(AsyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncRoomsResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncRoomsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncRoomsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncRoomsResourceWithStreamingResponse(self)
+
+ async def create_dm(
+ self,
+ identifier: str,
+ *,
+ bridge_id: str,
+ login_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RoomCreateDmResponse:
+ """
+ Create a direct chat with a user on the remote network.
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not identifier:
+ raise ValueError(f"Expected a non-empty value for `identifier` but received {identifier!r}")
+ return await self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/create_dm/{identifier}",
+ bridge_id=bridge_id,
+ identifier=identifier,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"login_id": login_id}, room_create_dm_params.RoomCreateDmParams),
+ ),
+ cast_to=RoomCreateDmResponse,
+ )
+
+ async def create_group(
+ self,
+ group_type: str,
+ *,
+ bridge_id: str,
+ login_id: str | Omit = omit,
+ avatar: room_create_group_params.Avatar | Omit = omit,
+ disappear: room_create_group_params.Disappear | Omit = omit,
+ name: room_create_group_params.Name | Omit = omit,
+ parent: object | Omit = omit,
+ participants: SequenceNotStr[str] | Omit = omit,
+ room_id: str | Omit = omit,
+ topic: room_create_group_params.Topic | Omit = omit,
+ type: str | Omit = omit,
+ username: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> RoomCreateGroupResponse:
+ """
+ Create a group chat on the remote network.
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ avatar: The `m.room.avatar` event content for the room.
+
+ disappear: The `com.beeper.disappearing_timer` event content for the room.
+
+ name: The `m.room.name` event content for the room.
+
+ participants: The users to add to the group initially.
+
+ room_id: An existing Matrix room ID to bridge to. The other parameters must be already in
+ sync with the room state when using this parameter.
+
+ topic: The `m.room.topic` event content for the room.
+
+ type: The type of group to create.
+
+ username: The public username for the created group.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not group_type:
+ raise ValueError(f"Expected a non-empty value for `group_type` but received {group_type!r}")
+ return await self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/create_group/{group_type}",
+ bridge_id=bridge_id,
+ group_type=group_type,
+ ),
+ body=await async_maybe_transform(
+ {
+ "avatar": avatar,
+ "disappear": disappear,
+ "name": name,
+ "parent": parent,
+ "participants": participants,
+ "room_id": room_id,
+ "topic": topic,
+ "type": type,
+ "username": username,
+ },
+ room_create_group_params.RoomCreateGroupParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"login_id": login_id}, room_create_group_params.RoomCreateGroupParams
+ ),
+ ),
+ cast_to=RoomCreateGroupResponse,
+ )
+
+
+class RoomsResourceWithRawResponse:
+ def __init__(self, rooms: RoomsResource) -> None:
+ self._rooms = rooms
+
+ self.create_dm = to_raw_response_wrapper(
+ rooms.create_dm,
+ )
+ self.create_group = to_raw_response_wrapper(
+ rooms.create_group,
+ )
+
+
+class AsyncRoomsResourceWithRawResponse:
+ def __init__(self, rooms: AsyncRoomsResource) -> None:
+ self._rooms = rooms
+
+ self.create_dm = async_to_raw_response_wrapper(
+ rooms.create_dm,
+ )
+ self.create_group = async_to_raw_response_wrapper(
+ rooms.create_group,
+ )
+
+
+class RoomsResourceWithStreamingResponse:
+ def __init__(self, rooms: RoomsResource) -> None:
+ self._rooms = rooms
+
+ self.create_dm = to_streamed_response_wrapper(
+ rooms.create_dm,
+ )
+ self.create_group = to_streamed_response_wrapper(
+ rooms.create_group,
+ )
+
+
+class AsyncRoomsResourceWithStreamingResponse:
+ def __init__(self, rooms: AsyncRoomsResource) -> None:
+ self._rooms = rooms
+
+ self.create_dm = async_to_streamed_response_wrapper(
+ rooms.create_dm,
+ )
+ self.create_group = async_to_streamed_response_wrapper(
+ rooms.create_group,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/bridges/users.py b/src/beeper_desktop_api/resources/matrix/bridges/users.py
new file mode 100644
index 0000000..541fc05
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/bridges/users.py
@@ -0,0 +1,304 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ...._utils import path_template, maybe_transform, async_maybe_transform
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+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.matrix.bridges import user_search_params, user_resolve_params
+from ....types.matrix.bridges.user_search_response import UserSearchResponse
+from ....types.matrix.bridges.user_resolve_response import UserResolveResponse
+
+__all__ = ["UsersResource", "AsyncUsersResource"]
+
+
+class UsersResource(SyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> UsersResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return UsersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> UsersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return UsersResourceWithStreamingResponse(self)
+
+ def resolve(
+ self,
+ identifier: str,
+ *,
+ bridge_id: str,
+ login_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> UserResolveResponse:
+ """
+ Resolve an identifier to a user on the remote network.
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not identifier:
+ raise ValueError(f"Expected a non-empty value for `identifier` but received {identifier!r}")
+ return self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/resolve_identifier/{identifier}",
+ bridge_id=bridge_id,
+ identifier=identifier,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"login_id": login_id}, user_resolve_params.UserResolveParams),
+ ),
+ cast_to=UserResolveResponse,
+ )
+
+ def search(
+ self,
+ bridge_id: str,
+ *,
+ login_id: str | Omit = omit,
+ query: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # 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,
+ ) -> UserSearchResponse:
+ """
+ Search for users on the remote network
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ query: The search query to send to the remote network
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/search_users",
+ bridge_id=bridge_id,
+ ),
+ body=maybe_transform({"query": query}, user_search_params.UserSearchParams),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"login_id": login_id}, user_search_params.UserSearchParams),
+ ),
+ cast_to=UserSearchResponse,
+ )
+
+
+class AsyncUsersResource(AsyncAPIResource):
+ """Matrix-compatible APIs for accounts and connected network bridges."""
+
+ @cached_property
+ def with_raw_response(self) -> AsyncUsersResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncUsersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncUsersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncUsersResourceWithStreamingResponse(self)
+
+ async def resolve(
+ self,
+ identifier: str,
+ *,
+ bridge_id: str,
+ login_id: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> UserResolveResponse:
+ """
+ Resolve an identifier to a user on the remote network.
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ if not identifier:
+ raise ValueError(f"Expected a non-empty value for `identifier` but received {identifier!r}")
+ return await self._get(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/resolve_identifier/{identifier}",
+ bridge_id=bridge_id,
+ identifier=identifier,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"login_id": login_id}, user_resolve_params.UserResolveParams),
+ ),
+ cast_to=UserResolveResponse,
+ )
+
+ async def search(
+ self,
+ bridge_id: str,
+ *,
+ login_id: str | Omit = omit,
+ query: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # 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,
+ ) -> UserSearchResponse:
+ """
+ Search for users on the remote network
+
+ Args:
+ login_id: An optional explicit login ID to do the action through.
+
+ query: The search query to send to the remote network
+
+ 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 bridge_id:
+ raise ValueError(f"Expected a non-empty value for `bridge_id` but received {bridge_id!r}")
+ return await self._post(
+ path_template(
+ "/_matrix/client/unstable/com.beeper.bridge/{bridge_id}/_matrix/provision/v3/search_users",
+ bridge_id=bridge_id,
+ ),
+ body=await async_maybe_transform({"query": query}, user_search_params.UserSearchParams),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"login_id": login_id}, user_search_params.UserSearchParams),
+ ),
+ cast_to=UserSearchResponse,
+ )
+
+
+class UsersResourceWithRawResponse:
+ def __init__(self, users: UsersResource) -> None:
+ self._users = users
+
+ self.resolve = to_raw_response_wrapper(
+ users.resolve,
+ )
+ self.search = to_raw_response_wrapper(
+ users.search,
+ )
+
+
+class AsyncUsersResourceWithRawResponse:
+ def __init__(self, users: AsyncUsersResource) -> None:
+ self._users = users
+
+ self.resolve = async_to_raw_response_wrapper(
+ users.resolve,
+ )
+ self.search = async_to_raw_response_wrapper(
+ users.search,
+ )
+
+
+class UsersResourceWithStreamingResponse:
+ def __init__(self, users: UsersResource) -> None:
+ self._users = users
+
+ self.resolve = to_streamed_response_wrapper(
+ users.resolve,
+ )
+ self.search = to_streamed_response_wrapper(
+ users.search,
+ )
+
+
+class AsyncUsersResourceWithStreamingResponse:
+ def __init__(self, users: AsyncUsersResource) -> None:
+ self._users = users
+
+ self.resolve = async_to_streamed_response_wrapper(
+ users.resolve,
+ )
+ self.search = async_to_streamed_response_wrapper(
+ users.search,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/matrix.py b/src/beeper_desktop_api/resources/matrix/matrix.py
new file mode 100644
index 0000000..8a494a3
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/matrix.py
@@ -0,0 +1,176 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from .rooms.rooms import (
+ RoomsResource,
+ AsyncRoomsResource,
+ RoomsResourceWithRawResponse,
+ AsyncRoomsResourceWithRawResponse,
+ RoomsResourceWithStreamingResponse,
+ AsyncRoomsResourceWithStreamingResponse,
+)
+from .users.users import (
+ UsersResource,
+ AsyncUsersResource,
+ UsersResourceWithRawResponse,
+ AsyncUsersResourceWithRawResponse,
+ UsersResourceWithStreamingResponse,
+ AsyncUsersResourceWithStreamingResponse,
+)
+from .bridges.bridges import (
+ BridgesResource,
+ AsyncBridgesResource,
+ BridgesResourceWithRawResponse,
+ AsyncBridgesResourceWithRawResponse,
+ BridgesResourceWithStreamingResponse,
+ AsyncBridgesResourceWithStreamingResponse,
+)
+
+__all__ = ["MatrixResource", "AsyncMatrixResource"]
+
+
+class MatrixResource(SyncAPIResource):
+ """Matrix-compatible APIs for accounts, rooms, and connected network bridges."""
+
+ @cached_property
+ def users(self) -> UsersResource:
+ return UsersResource(self._client)
+
+ @cached_property
+ def rooms(self) -> RoomsResource:
+ return RoomsResource(self._client)
+
+ @cached_property
+ def bridges(self) -> BridgesResource:
+ """Matrix-compatible APIs for connected network bridges."""
+ return BridgesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> MatrixResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return MatrixResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> MatrixResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return MatrixResourceWithStreamingResponse(self)
+
+
+class AsyncMatrixResource(AsyncAPIResource):
+ """Matrix-compatible APIs for accounts, rooms, and connected network bridges."""
+
+ @cached_property
+ def users(self) -> AsyncUsersResource:
+ return AsyncUsersResource(self._client)
+
+ @cached_property
+ def rooms(self) -> AsyncRoomsResource:
+ return AsyncRoomsResource(self._client)
+
+ @cached_property
+ def bridges(self) -> AsyncBridgesResource:
+ """Matrix-compatible APIs for connected network bridges."""
+ return AsyncBridgesResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncMatrixResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncMatrixResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncMatrixResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncMatrixResourceWithStreamingResponse(self)
+
+
+class MatrixResourceWithRawResponse:
+ def __init__(self, matrix: MatrixResource) -> None:
+ self._matrix = matrix
+
+ @cached_property
+ def users(self) -> UsersResourceWithRawResponse:
+ return UsersResourceWithRawResponse(self._matrix.users)
+
+ @cached_property
+ def rooms(self) -> RoomsResourceWithRawResponse:
+ return RoomsResourceWithRawResponse(self._matrix.rooms)
+
+ @cached_property
+ def bridges(self) -> BridgesResourceWithRawResponse:
+ """Matrix-compatible APIs for connected network bridges."""
+ return BridgesResourceWithRawResponse(self._matrix.bridges)
+
+
+class AsyncMatrixResourceWithRawResponse:
+ def __init__(self, matrix: AsyncMatrixResource) -> None:
+ self._matrix = matrix
+
+ @cached_property
+ def users(self) -> AsyncUsersResourceWithRawResponse:
+ return AsyncUsersResourceWithRawResponse(self._matrix.users)
+
+ @cached_property
+ def rooms(self) -> AsyncRoomsResourceWithRawResponse:
+ return AsyncRoomsResourceWithRawResponse(self._matrix.rooms)
+
+ @cached_property
+ def bridges(self) -> AsyncBridgesResourceWithRawResponse:
+ """Matrix-compatible APIs for connected network bridges."""
+ return AsyncBridgesResourceWithRawResponse(self._matrix.bridges)
+
+
+class MatrixResourceWithStreamingResponse:
+ def __init__(self, matrix: MatrixResource) -> None:
+ self._matrix = matrix
+
+ @cached_property
+ def users(self) -> UsersResourceWithStreamingResponse:
+ return UsersResourceWithStreamingResponse(self._matrix.users)
+
+ @cached_property
+ def rooms(self) -> RoomsResourceWithStreamingResponse:
+ return RoomsResourceWithStreamingResponse(self._matrix.rooms)
+
+ @cached_property
+ def bridges(self) -> BridgesResourceWithStreamingResponse:
+ """Matrix-compatible APIs for connected network bridges."""
+ return BridgesResourceWithStreamingResponse(self._matrix.bridges)
+
+
+class AsyncMatrixResourceWithStreamingResponse:
+ def __init__(self, matrix: AsyncMatrixResource) -> None:
+ self._matrix = matrix
+
+ @cached_property
+ def users(self) -> AsyncUsersResourceWithStreamingResponse:
+ return AsyncUsersResourceWithStreamingResponse(self._matrix.users)
+
+ @cached_property
+ def rooms(self) -> AsyncRoomsResourceWithStreamingResponse:
+ return AsyncRoomsResourceWithStreamingResponse(self._matrix.rooms)
+
+ @cached_property
+ def bridges(self) -> AsyncBridgesResourceWithStreamingResponse:
+ """Matrix-compatible APIs for connected network bridges."""
+ return AsyncBridgesResourceWithStreamingResponse(self._matrix.bridges)
diff --git a/src/beeper_desktop_api/resources/matrix/rooms/__init__.py b/src/beeper_desktop_api/resources/matrix/rooms/__init__.py
new file mode 100644
index 0000000..443fc1b
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/rooms/__init__.py
@@ -0,0 +1,61 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .rooms import (
+ RoomsResource,
+ AsyncRoomsResource,
+ RoomsResourceWithRawResponse,
+ AsyncRoomsResourceWithRawResponse,
+ RoomsResourceWithStreamingResponse,
+ AsyncRoomsResourceWithStreamingResponse,
+)
+from .state import (
+ StateResource,
+ AsyncStateResource,
+ StateResourceWithRawResponse,
+ AsyncStateResourceWithRawResponse,
+ StateResourceWithStreamingResponse,
+ AsyncStateResourceWithStreamingResponse,
+)
+from .events import (
+ EventsResource,
+ AsyncEventsResource,
+ EventsResourceWithRawResponse,
+ AsyncEventsResourceWithRawResponse,
+ EventsResourceWithStreamingResponse,
+ AsyncEventsResourceWithStreamingResponse,
+)
+from .account_data import (
+ AccountDataResource,
+ AsyncAccountDataResource,
+ AccountDataResourceWithRawResponse,
+ AsyncAccountDataResourceWithRawResponse,
+ AccountDataResourceWithStreamingResponse,
+ AsyncAccountDataResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "AccountDataResource",
+ "AsyncAccountDataResource",
+ "AccountDataResourceWithRawResponse",
+ "AsyncAccountDataResourceWithRawResponse",
+ "AccountDataResourceWithStreamingResponse",
+ "AsyncAccountDataResourceWithStreamingResponse",
+ "StateResource",
+ "AsyncStateResource",
+ "StateResourceWithRawResponse",
+ "AsyncStateResourceWithRawResponse",
+ "StateResourceWithStreamingResponse",
+ "AsyncStateResourceWithStreamingResponse",
+ "EventsResource",
+ "AsyncEventsResource",
+ "EventsResourceWithRawResponse",
+ "AsyncEventsResourceWithRawResponse",
+ "EventsResourceWithStreamingResponse",
+ "AsyncEventsResourceWithStreamingResponse",
+ "RoomsResource",
+ "AsyncRoomsResource",
+ "RoomsResourceWithRawResponse",
+ "AsyncRoomsResourceWithRawResponse",
+ "RoomsResourceWithStreamingResponse",
+ "AsyncRoomsResourceWithStreamingResponse",
+]
diff --git a/src/beeper_desktop_api/resources/matrix/rooms/account_data.py b/src/beeper_desktop_api/resources/matrix/rooms/account_data.py
new file mode 100644
index 0000000..967c27c
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/rooms/account_data.py
@@ -0,0 +1,302 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Query, Headers, NotGiven, not_given
+from ...._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 ...._base_client import make_request_options
+from ....types.matrix.rooms import account_data_update_params
+
+__all__ = ["AccountDataResource", "AsyncAccountDataResource"]
+
+
+class AccountDataResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AccountDataResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AccountDataResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AccountDataResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AccountDataResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ type: str,
+ *,
+ user_id: str,
+ room_id: 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,
+ ) -> object:
+ """Get some account data for the client on a given room.
+
+ This config is only
+ visible to the user that set the account data.
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ if not room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ if not type:
+ raise ValueError(f"Expected a non-empty value for `type` but received {type!r}")
+ return self._get(
+ path_template(
+ "/_matrix/client/v3/user/{user_id}/rooms/{room_id}/account_data/{type}",
+ user_id=user_id,
+ room_id=room_id,
+ type=type,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ def update(
+ self,
+ type: str,
+ *,
+ user_id: str,
+ room_id: str,
+ body: object,
+ # 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,
+ ) -> object:
+ """Set some account data for the client on a given room.
+
+ This config is only
+ visible to the user that set the account data. The config will be delivered to
+ clients in the per-room entries via
+ [/sync](https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv3sync).
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ if not room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ if not type:
+ raise ValueError(f"Expected a non-empty value for `type` but received {type!r}")
+ return self._put(
+ path_template(
+ "/_matrix/client/v3/user/{user_id}/rooms/{room_id}/account_data/{type}",
+ user_id=user_id,
+ room_id=room_id,
+ type=type,
+ ),
+ body=maybe_transform(body, account_data_update_params.AccountDataUpdateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+
+class AsyncAccountDataResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncAccountDataResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncAccountDataResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAccountDataResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncAccountDataResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ type: str,
+ *,
+ user_id: str,
+ room_id: 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,
+ ) -> object:
+ """Get some account data for the client on a given room.
+
+ This config is only
+ visible to the user that set the account data.
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ if not room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ if not type:
+ raise ValueError(f"Expected a non-empty value for `type` but received {type!r}")
+ return await self._get(
+ path_template(
+ "/_matrix/client/v3/user/{user_id}/rooms/{room_id}/account_data/{type}",
+ user_id=user_id,
+ room_id=room_id,
+ type=type,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ async def update(
+ self,
+ type: str,
+ *,
+ user_id: str,
+ room_id: str,
+ body: object,
+ # 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,
+ ) -> object:
+ """Set some account data for the client on a given room.
+
+ This config is only
+ visible to the user that set the account data. The config will be delivered to
+ clients in the per-room entries via
+ [/sync](https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv3sync).
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ if not room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ if not type:
+ raise ValueError(f"Expected a non-empty value for `type` but received {type!r}")
+ return await self._put(
+ path_template(
+ "/_matrix/client/v3/user/{user_id}/rooms/{room_id}/account_data/{type}",
+ user_id=user_id,
+ room_id=room_id,
+ type=type,
+ ),
+ body=await async_maybe_transform(body, account_data_update_params.AccountDataUpdateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+
+class AccountDataResourceWithRawResponse:
+ def __init__(self, account_data: AccountDataResource) -> None:
+ self._account_data = account_data
+
+ self.retrieve = to_raw_response_wrapper(
+ account_data.retrieve,
+ )
+ self.update = to_raw_response_wrapper(
+ account_data.update,
+ )
+
+
+class AsyncAccountDataResourceWithRawResponse:
+ def __init__(self, account_data: AsyncAccountDataResource) -> None:
+ self._account_data = account_data
+
+ self.retrieve = async_to_raw_response_wrapper(
+ account_data.retrieve,
+ )
+ self.update = async_to_raw_response_wrapper(
+ account_data.update,
+ )
+
+
+class AccountDataResourceWithStreamingResponse:
+ def __init__(self, account_data: AccountDataResource) -> None:
+ self._account_data = account_data
+
+ self.retrieve = to_streamed_response_wrapper(
+ account_data.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ account_data.update,
+ )
+
+
+class AsyncAccountDataResourceWithStreamingResponse:
+ def __init__(self, account_data: AsyncAccountDataResource) -> None:
+ self._account_data = account_data
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ account_data.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ account_data.update,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/rooms/events.py b/src/beeper_desktop_api/resources/matrix/rooms/events.py
new file mode 100644
index 0000000..c7dc565
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/rooms/events.py
@@ -0,0 +1,174 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Query, Headers, NotGiven, not_given
+from ...._utils import path_template
+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.matrix.rooms.event_retrieve_response import EventRetrieveResponse
+
+__all__ = ["EventsResource", "AsyncEventsResource"]
+
+
+class EventsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> EventsResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return EventsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> EventsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return EventsResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ event_id: str,
+ *,
+ room_id: 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,
+ ) -> EventRetrieveResponse:
+ """Get a single event based on `roomId/eventId`.
+
+ You must have permission to
+ retrieve this event e.g. by being a member in the room for this event.
+
+ 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 room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ if not event_id:
+ raise ValueError(f"Expected a non-empty value for `event_id` but received {event_id!r}")
+ return self._get(
+ path_template("/_matrix/client/v3/rooms/{room_id}/event/{event_id}", room_id=room_id, event_id=event_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=EventRetrieveResponse,
+ )
+
+
+class AsyncEventsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncEventsResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncEventsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncEventsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncEventsResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ event_id: str,
+ *,
+ room_id: 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,
+ ) -> EventRetrieveResponse:
+ """Get a single event based on `roomId/eventId`.
+
+ You must have permission to
+ retrieve this event e.g. by being a member in the room for this event.
+
+ 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 room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ if not event_id:
+ raise ValueError(f"Expected a non-empty value for `event_id` but received {event_id!r}")
+ return await self._get(
+ path_template("/_matrix/client/v3/rooms/{room_id}/event/{event_id}", room_id=room_id, event_id=event_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=EventRetrieveResponse,
+ )
+
+
+class EventsResourceWithRawResponse:
+ def __init__(self, events: EventsResource) -> None:
+ self._events = events
+
+ self.retrieve = to_raw_response_wrapper(
+ events.retrieve,
+ )
+
+
+class AsyncEventsResourceWithRawResponse:
+ def __init__(self, events: AsyncEventsResource) -> None:
+ self._events = events
+
+ self.retrieve = async_to_raw_response_wrapper(
+ events.retrieve,
+ )
+
+
+class EventsResourceWithStreamingResponse:
+ def __init__(self, events: EventsResource) -> None:
+ self._events = events
+
+ self.retrieve = to_streamed_response_wrapper(
+ events.retrieve,
+ )
+
+
+class AsyncEventsResourceWithStreamingResponse:
+ def __init__(self, events: AsyncEventsResource) -> None:
+ self._events = events
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ events.retrieve,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/rooms/rooms.py b/src/beeper_desktop_api/resources/matrix/rooms/rooms.py
new file mode 100644
index 0000000..2686e32
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/rooms/rooms.py
@@ -0,0 +1,845 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable
+from typing_extensions import Literal
+
+import httpx
+
+from .state import (
+ StateResource,
+ AsyncStateResource,
+ StateResourceWithRawResponse,
+ AsyncStateResourceWithRawResponse,
+ StateResourceWithStreamingResponse,
+ AsyncStateResourceWithStreamingResponse,
+)
+from .events import (
+ EventsResource,
+ AsyncEventsResource,
+ EventsResourceWithRawResponse,
+ AsyncEventsResourceWithRawResponse,
+ EventsResourceWithStreamingResponse,
+ AsyncEventsResourceWithStreamingResponse,
+)
+from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, 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 .account_data import (
+ AccountDataResource,
+ AsyncAccountDataResource,
+ AccountDataResourceWithRawResponse,
+ AsyncAccountDataResourceWithRawResponse,
+ AccountDataResourceWithStreamingResponse,
+ AsyncAccountDataResourceWithStreamingResponse,
+)
+from ...._base_client import make_request_options
+from ....types.matrix import room_join_params, room_leave_params, room_create_params
+from ....types.matrix.room_join_response import RoomJoinResponse
+from ....types.matrix.room_create_response import RoomCreateResponse
+
+__all__ = ["RoomsResource", "AsyncRoomsResource"]
+
+
+class RoomsResource(SyncAPIResource):
+ @cached_property
+ def account_data(self) -> AccountDataResource:
+ return AccountDataResource(self._client)
+
+ @cached_property
+ def state(self) -> StateResource:
+ return StateResource(self._client)
+
+ @cached_property
+ def events(self) -> EventsResource:
+ return EventsResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> RoomsResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return RoomsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> RoomsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return RoomsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ creation_content: object | Omit = omit,
+ initial_state: Iterable[room_create_params.InitialState] | Omit = omit,
+ invite: SequenceNotStr[str] | Omit = omit,
+ invite_3pid: Iterable[room_create_params.Invite3pid] | Omit = omit,
+ is_direct: bool | Omit = omit,
+ name: str | Omit = omit,
+ power_level_content_override: object | Omit = omit,
+ preset: Literal["private_chat", "public_chat", "trusted_private_chat"] | Omit = omit,
+ room_alias_name: str | Omit = omit,
+ room_version: str | Omit = omit,
+ topic: str | Omit = omit,
+ visibility: Literal["public", "private"] | 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,
+ ) -> RoomCreateResponse:
+ """
+ Create a new room with various configuration options.
+
+ The server MUST apply the normal state resolution rules when creating the new
+ room, including checking power levels for each event. It MUST apply the events
+ implied by the request in the following order:
+
+ 1. The `m.room.create` event itself. Must be the first event in the room.
+
+ 2. An `m.room.member` event for the creator to join the room. This is needed so
+ the remaining events can be sent.
+
+ 3. A default `m.room.power_levels` event. Overridden by the
+ `power_level_content_override` parameter.
+
+ In [room versions](https://spec.matrix.org/v1.18/rooms) 1 through 11, the
+ room creator (and not other members) will be given permission to send state
+ events.
+
+ In room versions 12 and later, the room creator is given infinite power level
+ and cannot be specified in the `users` field of `m.room.power_levels`, so is
+ not listed explicitly.
+
+ **Note**: For `trusted_private_chat`, the users specified in the `invite`
+ parameter SHOULD also be appended to `additional_creators` by the server, per
+ the `creation_content` parameter.
+
+ If the room's version is 12 or higher, the power level for sending
+ `m.room.tombstone` events MUST explicitly be higher than `state_default`. For
+ example, set to 150 instead of 100.
+
+ 4. An `m.room.canonical_alias` event if `room_alias_name` is given.
+
+ 5. Events set by the `preset`. Currently these are the `m.room.join_rules`,
+ `m.room.history_visibility`, and `m.room.guest_access` state events.
+
+ 6. Events listed in `initial_state`, in the order that they are listed.
+
+ 7. Events implied by `name` and `topic` (`m.room.name` and `m.room.topic` state
+ events).
+
+ 8. Invite events implied by `invite` and `invite_3pid` (`m.room.member` with
+ `membership: invite` and `m.room.third_party_invite`).
+
+ The available presets do the following with respect to room state:
+
+ | Preset | `join_rules` | `history_visibility` | `guest_access` | Other |
+ | ---------------------- | ------------ | -------------------- | -------------- | ---------------------------------------------------------------- |
+ | `private_chat` | `invite` | `shared` | `can_join` | |
+ | `trusted_private_chat` | `invite` | `shared` | `can_join` | All invitees are given the same power level as the room creator. |
+ | `public_chat` | `public` | `shared` | `forbidden` | |
+
+ The server will create a `m.room.create` event in the room with the requesting
+ user as the creator, alongside other keys provided in the `creation_content` or
+ implied by behaviour of `creation_content`.
+
+ Args:
+ creation_content: Extra keys, such as `m.federate`, to be added to the content of the
+ [`m.room.create`](https://spec.matrix.org/v1.18/client-server-api/#mroomcreate)
+ event.
+
+ The server will overwrite the following keys: `creator`, `room_version`. Future
+ versions of the specification may allow the server to overwrite other keys.
+
+ When using the `trusted_private_chat` preset, the server SHOULD combine
+ `additional_creators` specified here and the `invite` array into the eventual
+ `m.room.create` event's `additional_creators`, deduplicating between the two
+ parameters.
+
+ initial_state: A list of state events to set in the new room. This allows the user to override
+ the default state events set in the new room. The expected format of the state
+ events are an object with type, state_key and content keys set.
+
+ Takes precedence over events set by `preset`, but gets overridden by `name` and
+ `topic` keys.
+
+ invite: A list of user IDs to invite to the room. This will tell the server to invite
+ everyone in the list to the newly created room.
+
+ invite_3pid: A list of objects representing third-party IDs to invite into the room.
+
+ is_direct: This flag makes the server set the `is_direct` flag on the `m.room.member`
+ events sent to the users in `invite` and `invite_3pid`. See
+ [Direct Messaging](https://spec.matrix.org/v1.18/client-server-api/#direct-messaging)
+ for more information.
+
+ name: If this is included, an
+ [`m.room.name`](https://spec.matrix.org/v1.18/client-server-api/#mroomname)
+ event will be sent into the room to indicate the name for the room. This
+ overwrites any
+ [`m.room.name`](https://spec.matrix.org/v1.18/client-server-api/#mroomname)
+ event in `initial_state`.
+
+ power_level_content_override: The power level content to override in the default power level event. This
+ object is applied on top of the generated
+ [`m.room.power_levels`](https://spec.matrix.org/v1.18/client-server-api/#mroompower_levels)
+ event content prior to it being sent to the room. Defaults to overriding
+ nothing.
+
+ preset: Convenience parameter for setting various default state events based on a
+ preset.
+
+ If unspecified, the server should use the `visibility` to determine which preset
+ to use. A visibility of `public` equates to a preset of `public_chat` and
+ `private` visibility equates to a preset of `private_chat`.
+
+ room_alias_name: The desired room alias **local part**. If this is included, a room alias will be
+ created and mapped to the newly created room. The alias will belong on the
+ _same_ homeserver which created the room. For example, if this was set to "foo"
+ and sent to the homeserver "example.com" the complete room alias would be
+ `#foo:example.com`.
+
+ The complete room alias will become the canonical alias for the room and an
+ `m.room.canonical_alias` event will be sent into the room.
+
+ room_version: The room version to set for the room. If not provided, the homeserver is to use
+ its configured default. If provided, the homeserver will return a 400 error with
+ the errcode `M_UNSUPPORTED_ROOM_VERSION` if it does not support the room
+ version.
+
+ topic: If this is included, an
+ [`m.room.topic`](https://spec.matrix.org/v1.18/client-server-api/#mroomtopic)
+ event with a `text/plain` mimetype will be sent into the room to indicate the
+ topic for the room. This overwrites any
+ [`m.room.topic`](https://spec.matrix.org/v1.18/client-server-api/#mroomtopic)
+ event in `initial_state`.
+
+ visibility: The room's visibility in the server's
+ [published room directory](https://spec.matrix.org/v1.18/client-server-api#published-room-directory).
+ Defaults to `private`.
+
+ 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(
+ "/_matrix/client/v3/createRoom",
+ body=maybe_transform(
+ {
+ "creation_content": creation_content,
+ "initial_state": initial_state,
+ "invite": invite,
+ "invite_3pid": invite_3pid,
+ "is_direct": is_direct,
+ "name": name,
+ "power_level_content_override": power_level_content_override,
+ "preset": preset,
+ "room_alias_name": room_alias_name,
+ "room_version": room_version,
+ "topic": topic,
+ "visibility": visibility,
+ },
+ room_create_params.RoomCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RoomCreateResponse,
+ )
+
+ def join(
+ self,
+ room_id_or_alias: str,
+ *,
+ via: SequenceNotStr[str] | Omit = omit,
+ reason: str | Omit = omit,
+ third_party_signed: room_join_params.ThirdPartySigned | 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,
+ ) -> RoomJoinResponse:
+ """
+ _Note that this API takes either a room ID or alias, unlike_
+ `/rooms/{roomId}/join`.
+
+ This API starts a user's participation in a particular room, if that user is
+ allowed to participate in that room. After this call, the client is allowed to
+ see all current state events in the room, and all subsequent events associated
+ with the room until the user leaves the room.
+
+ After a user has joined a room, the room will appear as an entry in the response
+ of the
+ [`/initialSync`](https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv3initialsync)
+ and
+ [`/sync`](https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv3sync)
+ APIs.
+
+ Args:
+ via: The servers to attempt to join the room through. One of the servers must be
+ participating in the room.
+
+ reason: Optional reason to be included as the `reason` on the subsequent membership
+ event.
+
+ third_party_signed: A signature of an `m.third_party_invite` token to prove that this user owns a
+ third-party identity which has been invited to the room.
+
+ 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 room_id_or_alias:
+ raise ValueError(f"Expected a non-empty value for `room_id_or_alias` but received {room_id_or_alias!r}")
+ return self._post(
+ path_template("/_matrix/client/v3/join/{room_id_or_alias}", room_id_or_alias=room_id_or_alias),
+ body=maybe_transform(
+ {
+ "reason": reason,
+ "third_party_signed": third_party_signed,
+ },
+ room_join_params.RoomJoinParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"via": via}, room_join_params.RoomJoinParams),
+ ),
+ cast_to=RoomJoinResponse,
+ )
+
+ def leave(
+ self,
+ room_id: str,
+ *,
+ reason: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> object:
+ """
+ This API stops a user participating in a particular room.
+
+ If the user was already in the room, they will no longer be able to see new
+ events in the room. If the room requires an invite to join, they will need to be
+ re-invited before they can re-join.
+
+ If the user was invited to the room, but had not joined, this call serves to
+ reject the invite.
+
+ Servers MAY additionally forget the room when this endpoint is called – just as
+ if the user had also invoked
+ [`/forget`](https://spec.matrix.org/v1.18/client-server-api/#post_matrixclientv3roomsroomidforget).
+ Servers that do this, MUST inform clients about this behavior using the
+ [`m.forget_forced_upon_leave`](https://spec.matrix.org/v1.18/client-server-api/#mforget_forced_upon_leave-capability)
+ capability.
+
+ If the server doesn't automatically forget the room, the user will still be
+ allowed to retrieve history from the room which they were previously allowed to
+ see.
+
+ Args:
+ reason: Optional reason to be included as the `reason` on the subsequent membership
+ event.
+
+ 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 room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ return self._post(
+ path_template("/_matrix/client/v3/rooms/{room_id}/leave", room_id=room_id),
+ body=maybe_transform({"reason": reason}, room_leave_params.RoomLeaveParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+
+class AsyncRoomsResource(AsyncAPIResource):
+ @cached_property
+ def account_data(self) -> AsyncAccountDataResource:
+ return AsyncAccountDataResource(self._client)
+
+ @cached_property
+ def state(self) -> AsyncStateResource:
+ return AsyncStateResource(self._client)
+
+ @cached_property
+ def events(self) -> AsyncEventsResource:
+ return AsyncEventsResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncRoomsResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncRoomsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncRoomsResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncRoomsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ creation_content: object | Omit = omit,
+ initial_state: Iterable[room_create_params.InitialState] | Omit = omit,
+ invite: SequenceNotStr[str] | Omit = omit,
+ invite_3pid: Iterable[room_create_params.Invite3pid] | Omit = omit,
+ is_direct: bool | Omit = omit,
+ name: str | Omit = omit,
+ power_level_content_override: object | Omit = omit,
+ preset: Literal["private_chat", "public_chat", "trusted_private_chat"] | Omit = omit,
+ room_alias_name: str | Omit = omit,
+ room_version: str | Omit = omit,
+ topic: str | Omit = omit,
+ visibility: Literal["public", "private"] | 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,
+ ) -> RoomCreateResponse:
+ """
+ Create a new room with various configuration options.
+
+ The server MUST apply the normal state resolution rules when creating the new
+ room, including checking power levels for each event. It MUST apply the events
+ implied by the request in the following order:
+
+ 1. The `m.room.create` event itself. Must be the first event in the room.
+
+ 2. An `m.room.member` event for the creator to join the room. This is needed so
+ the remaining events can be sent.
+
+ 3. A default `m.room.power_levels` event. Overridden by the
+ `power_level_content_override` parameter.
+
+ In [room versions](https://spec.matrix.org/v1.18/rooms) 1 through 11, the
+ room creator (and not other members) will be given permission to send state
+ events.
+
+ In room versions 12 and later, the room creator is given infinite power level
+ and cannot be specified in the `users` field of `m.room.power_levels`, so is
+ not listed explicitly.
+
+ **Note**: For `trusted_private_chat`, the users specified in the `invite`
+ parameter SHOULD also be appended to `additional_creators` by the server, per
+ the `creation_content` parameter.
+
+ If the room's version is 12 or higher, the power level for sending
+ `m.room.tombstone` events MUST explicitly be higher than `state_default`. For
+ example, set to 150 instead of 100.
+
+ 4. An `m.room.canonical_alias` event if `room_alias_name` is given.
+
+ 5. Events set by the `preset`. Currently these are the `m.room.join_rules`,
+ `m.room.history_visibility`, and `m.room.guest_access` state events.
+
+ 6. Events listed in `initial_state`, in the order that they are listed.
+
+ 7. Events implied by `name` and `topic` (`m.room.name` and `m.room.topic` state
+ events).
+
+ 8. Invite events implied by `invite` and `invite_3pid` (`m.room.member` with
+ `membership: invite` and `m.room.third_party_invite`).
+
+ The available presets do the following with respect to room state:
+
+ | Preset | `join_rules` | `history_visibility` | `guest_access` | Other |
+ | ---------------------- | ------------ | -------------------- | -------------- | ---------------------------------------------------------------- |
+ | `private_chat` | `invite` | `shared` | `can_join` | |
+ | `trusted_private_chat` | `invite` | `shared` | `can_join` | All invitees are given the same power level as the room creator. |
+ | `public_chat` | `public` | `shared` | `forbidden` | |
+
+ The server will create a `m.room.create` event in the room with the requesting
+ user as the creator, alongside other keys provided in the `creation_content` or
+ implied by behaviour of `creation_content`.
+
+ Args:
+ creation_content: Extra keys, such as `m.federate`, to be added to the content of the
+ [`m.room.create`](https://spec.matrix.org/v1.18/client-server-api/#mroomcreate)
+ event.
+
+ The server will overwrite the following keys: `creator`, `room_version`. Future
+ versions of the specification may allow the server to overwrite other keys.
+
+ When using the `trusted_private_chat` preset, the server SHOULD combine
+ `additional_creators` specified here and the `invite` array into the eventual
+ `m.room.create` event's `additional_creators`, deduplicating between the two
+ parameters.
+
+ initial_state: A list of state events to set in the new room. This allows the user to override
+ the default state events set in the new room. The expected format of the state
+ events are an object with type, state_key and content keys set.
+
+ Takes precedence over events set by `preset`, but gets overridden by `name` and
+ `topic` keys.
+
+ invite: A list of user IDs to invite to the room. This will tell the server to invite
+ everyone in the list to the newly created room.
+
+ invite_3pid: A list of objects representing third-party IDs to invite into the room.
+
+ is_direct: This flag makes the server set the `is_direct` flag on the `m.room.member`
+ events sent to the users in `invite` and `invite_3pid`. See
+ [Direct Messaging](https://spec.matrix.org/v1.18/client-server-api/#direct-messaging)
+ for more information.
+
+ name: If this is included, an
+ [`m.room.name`](https://spec.matrix.org/v1.18/client-server-api/#mroomname)
+ event will be sent into the room to indicate the name for the room. This
+ overwrites any
+ [`m.room.name`](https://spec.matrix.org/v1.18/client-server-api/#mroomname)
+ event in `initial_state`.
+
+ power_level_content_override: The power level content to override in the default power level event. This
+ object is applied on top of the generated
+ [`m.room.power_levels`](https://spec.matrix.org/v1.18/client-server-api/#mroompower_levels)
+ event content prior to it being sent to the room. Defaults to overriding
+ nothing.
+
+ preset: Convenience parameter for setting various default state events based on a
+ preset.
+
+ If unspecified, the server should use the `visibility` to determine which preset
+ to use. A visibility of `public` equates to a preset of `public_chat` and
+ `private` visibility equates to a preset of `private_chat`.
+
+ room_alias_name: The desired room alias **local part**. If this is included, a room alias will be
+ created and mapped to the newly created room. The alias will belong on the
+ _same_ homeserver which created the room. For example, if this was set to "foo"
+ and sent to the homeserver "example.com" the complete room alias would be
+ `#foo:example.com`.
+
+ The complete room alias will become the canonical alias for the room and an
+ `m.room.canonical_alias` event will be sent into the room.
+
+ room_version: The room version to set for the room. If not provided, the homeserver is to use
+ its configured default. If provided, the homeserver will return a 400 error with
+ the errcode `M_UNSUPPORTED_ROOM_VERSION` if it does not support the room
+ version.
+
+ topic: If this is included, an
+ [`m.room.topic`](https://spec.matrix.org/v1.18/client-server-api/#mroomtopic)
+ event with a `text/plain` mimetype will be sent into the room to indicate the
+ topic for the room. This overwrites any
+ [`m.room.topic`](https://spec.matrix.org/v1.18/client-server-api/#mroomtopic)
+ event in `initial_state`.
+
+ visibility: The room's visibility in the server's
+ [published room directory](https://spec.matrix.org/v1.18/client-server-api#published-room-directory).
+ Defaults to `private`.
+
+ 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(
+ "/_matrix/client/v3/createRoom",
+ body=await async_maybe_transform(
+ {
+ "creation_content": creation_content,
+ "initial_state": initial_state,
+ "invite": invite,
+ "invite_3pid": invite_3pid,
+ "is_direct": is_direct,
+ "name": name,
+ "power_level_content_override": power_level_content_override,
+ "preset": preset,
+ "room_alias_name": room_alias_name,
+ "room_version": room_version,
+ "topic": topic,
+ "visibility": visibility,
+ },
+ room_create_params.RoomCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=RoomCreateResponse,
+ )
+
+ async def join(
+ self,
+ room_id_or_alias: str,
+ *,
+ via: SequenceNotStr[str] | Omit = omit,
+ reason: str | Omit = omit,
+ third_party_signed: room_join_params.ThirdPartySigned | 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,
+ ) -> RoomJoinResponse:
+ """
+ _Note that this API takes either a room ID or alias, unlike_
+ `/rooms/{roomId}/join`.
+
+ This API starts a user's participation in a particular room, if that user is
+ allowed to participate in that room. After this call, the client is allowed to
+ see all current state events in the room, and all subsequent events associated
+ with the room until the user leaves the room.
+
+ After a user has joined a room, the room will appear as an entry in the response
+ of the
+ [`/initialSync`](https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv3initialsync)
+ and
+ [`/sync`](https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv3sync)
+ APIs.
+
+ Args:
+ via: The servers to attempt to join the room through. One of the servers must be
+ participating in the room.
+
+ reason: Optional reason to be included as the `reason` on the subsequent membership
+ event.
+
+ third_party_signed: A signature of an `m.third_party_invite` token to prove that this user owns a
+ third-party identity which has been invited to the room.
+
+ 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 room_id_or_alias:
+ raise ValueError(f"Expected a non-empty value for `room_id_or_alias` but received {room_id_or_alias!r}")
+ return await self._post(
+ path_template("/_matrix/client/v3/join/{room_id_or_alias}", room_id_or_alias=room_id_or_alias),
+ body=await async_maybe_transform(
+ {
+ "reason": reason,
+ "third_party_signed": third_party_signed,
+ },
+ room_join_params.RoomJoinParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"via": via}, room_join_params.RoomJoinParams),
+ ),
+ cast_to=RoomJoinResponse,
+ )
+
+ async def leave(
+ self,
+ room_id: str,
+ *,
+ reason: str | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> object:
+ """
+ This API stops a user participating in a particular room.
+
+ If the user was already in the room, they will no longer be able to see new
+ events in the room. If the room requires an invite to join, they will need to be
+ re-invited before they can re-join.
+
+ If the user was invited to the room, but had not joined, this call serves to
+ reject the invite.
+
+ Servers MAY additionally forget the room when this endpoint is called – just as
+ if the user had also invoked
+ [`/forget`](https://spec.matrix.org/v1.18/client-server-api/#post_matrixclientv3roomsroomidforget).
+ Servers that do this, MUST inform clients about this behavior using the
+ [`m.forget_forced_upon_leave`](https://spec.matrix.org/v1.18/client-server-api/#mforget_forced_upon_leave-capability)
+ capability.
+
+ If the server doesn't automatically forget the room, the user will still be
+ allowed to retrieve history from the room which they were previously allowed to
+ see.
+
+ Args:
+ reason: Optional reason to be included as the `reason` on the subsequent membership
+ event.
+
+ 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 room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ return await self._post(
+ path_template("/_matrix/client/v3/rooms/{room_id}/leave", room_id=room_id),
+ body=await async_maybe_transform({"reason": reason}, room_leave_params.RoomLeaveParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+
+class RoomsResourceWithRawResponse:
+ def __init__(self, rooms: RoomsResource) -> None:
+ self._rooms = rooms
+
+ self.create = to_raw_response_wrapper(
+ rooms.create,
+ )
+ self.join = to_raw_response_wrapper(
+ rooms.join,
+ )
+ self.leave = to_raw_response_wrapper(
+ rooms.leave,
+ )
+
+ @cached_property
+ def account_data(self) -> AccountDataResourceWithRawResponse:
+ return AccountDataResourceWithRawResponse(self._rooms.account_data)
+
+ @cached_property
+ def state(self) -> StateResourceWithRawResponse:
+ return StateResourceWithRawResponse(self._rooms.state)
+
+ @cached_property
+ def events(self) -> EventsResourceWithRawResponse:
+ return EventsResourceWithRawResponse(self._rooms.events)
+
+
+class AsyncRoomsResourceWithRawResponse:
+ def __init__(self, rooms: AsyncRoomsResource) -> None:
+ self._rooms = rooms
+
+ self.create = async_to_raw_response_wrapper(
+ rooms.create,
+ )
+ self.join = async_to_raw_response_wrapper(
+ rooms.join,
+ )
+ self.leave = async_to_raw_response_wrapper(
+ rooms.leave,
+ )
+
+ @cached_property
+ def account_data(self) -> AsyncAccountDataResourceWithRawResponse:
+ return AsyncAccountDataResourceWithRawResponse(self._rooms.account_data)
+
+ @cached_property
+ def state(self) -> AsyncStateResourceWithRawResponse:
+ return AsyncStateResourceWithRawResponse(self._rooms.state)
+
+ @cached_property
+ def events(self) -> AsyncEventsResourceWithRawResponse:
+ return AsyncEventsResourceWithRawResponse(self._rooms.events)
+
+
+class RoomsResourceWithStreamingResponse:
+ def __init__(self, rooms: RoomsResource) -> None:
+ self._rooms = rooms
+
+ self.create = to_streamed_response_wrapper(
+ rooms.create,
+ )
+ self.join = to_streamed_response_wrapper(
+ rooms.join,
+ )
+ self.leave = to_streamed_response_wrapper(
+ rooms.leave,
+ )
+
+ @cached_property
+ def account_data(self) -> AccountDataResourceWithStreamingResponse:
+ return AccountDataResourceWithStreamingResponse(self._rooms.account_data)
+
+ @cached_property
+ def state(self) -> StateResourceWithStreamingResponse:
+ return StateResourceWithStreamingResponse(self._rooms.state)
+
+ @cached_property
+ def events(self) -> EventsResourceWithStreamingResponse:
+ return EventsResourceWithStreamingResponse(self._rooms.events)
+
+
+class AsyncRoomsResourceWithStreamingResponse:
+ def __init__(self, rooms: AsyncRoomsResource) -> None:
+ self._rooms = rooms
+
+ self.create = async_to_streamed_response_wrapper(
+ rooms.create,
+ )
+ self.join = async_to_streamed_response_wrapper(
+ rooms.join,
+ )
+ self.leave = async_to_streamed_response_wrapper(
+ rooms.leave,
+ )
+
+ @cached_property
+ def account_data(self) -> AsyncAccountDataResourceWithStreamingResponse:
+ return AsyncAccountDataResourceWithStreamingResponse(self._rooms.account_data)
+
+ @cached_property
+ def state(self) -> AsyncStateResourceWithStreamingResponse:
+ return AsyncStateResourceWithStreamingResponse(self._rooms.state)
+
+ @cached_property
+ def events(self) -> AsyncEventsResourceWithStreamingResponse:
+ return AsyncEventsResourceWithStreamingResponse(self._rooms.events)
diff --git a/src/beeper_desktop_api/resources/matrix/rooms/state.py b/src/beeper_desktop_api/resources/matrix/rooms/state.py
new file mode 100644
index 0000000..dc7f15f
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/rooms/state.py
@@ -0,0 +1,294 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal
+
+import httpx
+
+from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
+from ...._utils import path_template, maybe_transform, async_maybe_transform
+from ...._compat import cached_property
+from ...._resource import SyncAPIResource, AsyncAPIResource
+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.matrix.rooms import state_retrieve_params
+from ....types.matrix.rooms.state_list_response import StateListResponse
+from ....types.matrix.rooms.state_retrieve_response import StateRetrieveResponse
+
+__all__ = ["StateResource", "AsyncStateResource"]
+
+
+class StateResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> StateResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return StateResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> StateResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return StateResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ state_key: str,
+ *,
+ room_id: str,
+ event_type: str,
+ format: Literal["content", "event"] | 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,
+ ) -> StateRetrieveResponse:
+ """Looks up the contents of a state event in a room.
+
+ If the user is joined to the
+ room then the state is taken from the current state of the room. If the user has
+ left the room then the state is taken from the state of the room when they left.
+
+ Args:
+ format: The format to use for the returned data. `content` (the default) will return
+ only the content of the state event. `event` will return the entire event in the
+ usual format suitable for clients, including fields like event ID, sender and
+ timestamp.
+
+ 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 room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ if not event_type:
+ raise ValueError(f"Expected a non-empty value for `event_type` but received {event_type!r}")
+ if not state_key:
+ raise ValueError(f"Expected a non-empty value for `state_key` but received {state_key!r}")
+ return self._get(
+ path_template(
+ "/_matrix/client/v3/rooms/{room_id}/state/{event_type}/{state_key}",
+ room_id=room_id,
+ event_type=event_type,
+ state_key=state_key,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"format": format}, state_retrieve_params.StateRetrieveParams),
+ ),
+ cast_to=StateRetrieveResponse,
+ )
+
+ def list(
+ self,
+ room_id: 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,
+ ) -> StateListResponse:
+ """
+ Get the state events for the current state of a room.
+
+ 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 room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ return self._get(
+ path_template("/_matrix/client/v3/rooms/{room_id}/state", room_id=room_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=StateListResponse,
+ )
+
+
+class AsyncStateResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncStateResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncStateResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncStateResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncStateResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ state_key: str,
+ *,
+ room_id: str,
+ event_type: str,
+ format: Literal["content", "event"] | 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,
+ ) -> StateRetrieveResponse:
+ """Looks up the contents of a state event in a room.
+
+ If the user is joined to the
+ room then the state is taken from the current state of the room. If the user has
+ left the room then the state is taken from the state of the room when they left.
+
+ Args:
+ format: The format to use for the returned data. `content` (the default) will return
+ only the content of the state event. `event` will return the entire event in the
+ usual format suitable for clients, including fields like event ID, sender and
+ timestamp.
+
+ 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 room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ if not event_type:
+ raise ValueError(f"Expected a non-empty value for `event_type` but received {event_type!r}")
+ if not state_key:
+ raise ValueError(f"Expected a non-empty value for `state_key` but received {state_key!r}")
+ return await self._get(
+ path_template(
+ "/_matrix/client/v3/rooms/{room_id}/state/{event_type}/{state_key}",
+ room_id=room_id,
+ event_type=event_type,
+ state_key=state_key,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"format": format}, state_retrieve_params.StateRetrieveParams),
+ ),
+ cast_to=StateRetrieveResponse,
+ )
+
+ async def list(
+ self,
+ room_id: 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,
+ ) -> StateListResponse:
+ """
+ Get the state events for the current state of a room.
+
+ 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 room_id:
+ raise ValueError(f"Expected a non-empty value for `room_id` but received {room_id!r}")
+ return await self._get(
+ path_template("/_matrix/client/v3/rooms/{room_id}/state", room_id=room_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=StateListResponse,
+ )
+
+
+class StateResourceWithRawResponse:
+ def __init__(self, state: StateResource) -> None:
+ self._state = state
+
+ self.retrieve = to_raw_response_wrapper(
+ state.retrieve,
+ )
+ self.list = to_raw_response_wrapper(
+ state.list,
+ )
+
+
+class AsyncStateResourceWithRawResponse:
+ def __init__(self, state: AsyncStateResource) -> None:
+ self._state = state
+
+ self.retrieve = async_to_raw_response_wrapper(
+ state.retrieve,
+ )
+ self.list = async_to_raw_response_wrapper(
+ state.list,
+ )
+
+
+class StateResourceWithStreamingResponse:
+ def __init__(self, state: StateResource) -> None:
+ self._state = state
+
+ self.retrieve = to_streamed_response_wrapper(
+ state.retrieve,
+ )
+ self.list = to_streamed_response_wrapper(
+ state.list,
+ )
+
+
+class AsyncStateResourceWithStreamingResponse:
+ def __init__(self, state: AsyncStateResource) -> None:
+ self._state = state
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ state.retrieve,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ state.list,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/users/__init__.py b/src/beeper_desktop_api/resources/matrix/users/__init__.py
new file mode 100644
index 0000000..84ad0d9
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/users/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .users import (
+ UsersResource,
+ AsyncUsersResource,
+ UsersResourceWithRawResponse,
+ AsyncUsersResourceWithRawResponse,
+ UsersResourceWithStreamingResponse,
+ AsyncUsersResourceWithStreamingResponse,
+)
+from .account_data import (
+ AccountDataResource,
+ AsyncAccountDataResource,
+ AccountDataResourceWithRawResponse,
+ AsyncAccountDataResourceWithRawResponse,
+ AccountDataResourceWithStreamingResponse,
+ AsyncAccountDataResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "AccountDataResource",
+ "AsyncAccountDataResource",
+ "AccountDataResourceWithRawResponse",
+ "AsyncAccountDataResourceWithRawResponse",
+ "AccountDataResourceWithStreamingResponse",
+ "AsyncAccountDataResourceWithStreamingResponse",
+ "UsersResource",
+ "AsyncUsersResource",
+ "UsersResourceWithRawResponse",
+ "AsyncUsersResourceWithRawResponse",
+ "UsersResourceWithStreamingResponse",
+ "AsyncUsersResourceWithStreamingResponse",
+]
diff --git a/src/beeper_desktop_api/resources/matrix/users/account_data.py b/src/beeper_desktop_api/resources/matrix/users/account_data.py
new file mode 100644
index 0000000..2c8a316
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/users/account_data.py
@@ -0,0 +1,270 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Query, Headers, NotGiven, not_given
+from ...._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 ...._base_client import make_request_options
+from ....types.matrix.users import account_data_update_params
+
+__all__ = ["AccountDataResource", "AsyncAccountDataResource"]
+
+
+class AccountDataResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AccountDataResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AccountDataResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AccountDataResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AccountDataResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ type: str,
+ *,
+ user_id: 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,
+ ) -> object:
+ """Get some account data for the client.
+
+ This config is only visible to the user
+ that set the account data.
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ if not type:
+ raise ValueError(f"Expected a non-empty value for `type` but received {type!r}")
+ return self._get(
+ path_template("/_matrix/client/v3/user/{user_id}/account_data/{type}", user_id=user_id, type=type),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ def update(
+ self,
+ type: str,
+ *,
+ user_id: str,
+ body: object,
+ # 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,
+ ) -> object:
+ """Set some account data for the client.
+
+ This config is only visible to the user
+ that set the account data. The config will be available to clients through the
+ top-level `account_data` field in the homeserver response to
+ [/sync](https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv3sync).
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ if not type:
+ raise ValueError(f"Expected a non-empty value for `type` but received {type!r}")
+ return self._put(
+ path_template("/_matrix/client/v3/user/{user_id}/account_data/{type}", user_id=user_id, type=type),
+ body=maybe_transform(body, account_data_update_params.AccountDataUpdateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+
+class AsyncAccountDataResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncAccountDataResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncAccountDataResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAccountDataResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncAccountDataResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ type: str,
+ *,
+ user_id: 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,
+ ) -> object:
+ """Get some account data for the client.
+
+ This config is only visible to the user
+ that set the account data.
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ if not type:
+ raise ValueError(f"Expected a non-empty value for `type` but received {type!r}")
+ return await self._get(
+ path_template("/_matrix/client/v3/user/{user_id}/account_data/{type}", user_id=user_id, type=type),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+ async def update(
+ self,
+ type: str,
+ *,
+ user_id: str,
+ body: object,
+ # 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,
+ ) -> object:
+ """Set some account data for the client.
+
+ This config is only visible to the user
+ that set the account data. The config will be available to clients through the
+ top-level `account_data` field in the homeserver response to
+ [/sync](https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv3sync).
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ if not type:
+ raise ValueError(f"Expected a non-empty value for `type` but received {type!r}")
+ return await self._put(
+ path_template("/_matrix/client/v3/user/{user_id}/account_data/{type}", user_id=user_id, type=type),
+ body=await async_maybe_transform(body, account_data_update_params.AccountDataUpdateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=object,
+ )
+
+
+class AccountDataResourceWithRawResponse:
+ def __init__(self, account_data: AccountDataResource) -> None:
+ self._account_data = account_data
+
+ self.retrieve = to_raw_response_wrapper(
+ account_data.retrieve,
+ )
+ self.update = to_raw_response_wrapper(
+ account_data.update,
+ )
+
+
+class AsyncAccountDataResourceWithRawResponse:
+ def __init__(self, account_data: AsyncAccountDataResource) -> None:
+ self._account_data = account_data
+
+ self.retrieve = async_to_raw_response_wrapper(
+ account_data.retrieve,
+ )
+ self.update = async_to_raw_response_wrapper(
+ account_data.update,
+ )
+
+
+class AccountDataResourceWithStreamingResponse:
+ def __init__(self, account_data: AccountDataResource) -> None:
+ self._account_data = account_data
+
+ self.retrieve = to_streamed_response_wrapper(
+ account_data.retrieve,
+ )
+ self.update = to_streamed_response_wrapper(
+ account_data.update,
+ )
+
+
+class AsyncAccountDataResourceWithStreamingResponse:
+ def __init__(self, account_data: AsyncAccountDataResource) -> None:
+ self._account_data = account_data
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ account_data.retrieve,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ account_data.update,
+ )
diff --git a/src/beeper_desktop_api/resources/matrix/users/users.py b/src/beeper_desktop_api/resources/matrix/users/users.py
new file mode 100644
index 0000000..f7bdfb6
--- /dev/null
+++ b/src/beeper_desktop_api/resources/matrix/users/users.py
@@ -0,0 +1,196 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ...._types import Body, Query, Headers, NotGiven, not_given
+from ...._utils import path_template
+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 .account_data import (
+ AccountDataResource,
+ AsyncAccountDataResource,
+ AccountDataResourceWithRawResponse,
+ AsyncAccountDataResourceWithRawResponse,
+ AccountDataResourceWithStreamingResponse,
+ AsyncAccountDataResourceWithStreamingResponse,
+)
+from ...._base_client import make_request_options
+from ....types.matrix.user_retrieve_profile_response import UserRetrieveProfileResponse
+
+__all__ = ["UsersResource", "AsyncUsersResource"]
+
+
+class UsersResource(SyncAPIResource):
+ @cached_property
+ def account_data(self) -> AccountDataResource:
+ return AccountDataResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> UsersResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return UsersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> UsersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return UsersResourceWithStreamingResponse(self)
+
+ def retrieve_profile(
+ self,
+ user_id: 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,
+ ) -> UserRetrieveProfileResponse:
+ """
+ Get the complete profile for a user.
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ return self._get(
+ path_template("/_matrix/client/v3/profile/{user_id}", user_id=user_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=UserRetrieveProfileResponse,
+ )
+
+
+class AsyncUsersResource(AsyncAPIResource):
+ @cached_property
+ def account_data(self) -> AsyncAccountDataResource:
+ return AsyncAccountDataResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncUsersResourceWithRawResponse:
+ """
+ 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/beeper/desktop-api-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncUsersResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncUsersResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/beeper/desktop-api-python#with_streaming_response
+ """
+ return AsyncUsersResourceWithStreamingResponse(self)
+
+ async def retrieve_profile(
+ self,
+ user_id: 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,
+ ) -> UserRetrieveProfileResponse:
+ """
+ Get the complete profile for a user.
+
+ 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 user_id:
+ raise ValueError(f"Expected a non-empty value for `user_id` but received {user_id!r}")
+ return await self._get(
+ path_template("/_matrix/client/v3/profile/{user_id}", user_id=user_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=UserRetrieveProfileResponse,
+ )
+
+
+class UsersResourceWithRawResponse:
+ def __init__(self, users: UsersResource) -> None:
+ self._users = users
+
+ self.retrieve_profile = to_raw_response_wrapper(
+ users.retrieve_profile,
+ )
+
+ @cached_property
+ def account_data(self) -> AccountDataResourceWithRawResponse:
+ return AccountDataResourceWithRawResponse(self._users.account_data)
+
+
+class AsyncUsersResourceWithRawResponse:
+ def __init__(self, users: AsyncUsersResource) -> None:
+ self._users = users
+
+ self.retrieve_profile = async_to_raw_response_wrapper(
+ users.retrieve_profile,
+ )
+
+ @cached_property
+ def account_data(self) -> AsyncAccountDataResourceWithRawResponse:
+ return AsyncAccountDataResourceWithRawResponse(self._users.account_data)
+
+
+class UsersResourceWithStreamingResponse:
+ def __init__(self, users: UsersResource) -> None:
+ self._users = users
+
+ self.retrieve_profile = to_streamed_response_wrapper(
+ users.retrieve_profile,
+ )
+
+ @cached_property
+ def account_data(self) -> AccountDataResourceWithStreamingResponse:
+ return AccountDataResourceWithStreamingResponse(self._users.account_data)
+
+
+class AsyncUsersResourceWithStreamingResponse:
+ def __init__(self, users: AsyncUsersResource) -> None:
+ self._users = users
+
+ self.retrieve_profile = async_to_streamed_response_wrapper(
+ users.retrieve_profile,
+ )
+
+ @cached_property
+ def account_data(self) -> AsyncAccountDataResourceWithStreamingResponse:
+ return AsyncAccountDataResourceWithStreamingResponse(self._users.account_data)
diff --git a/src/beeper_desktop_api/types/__init__.py b/src/beeper_desktop_api/types/__init__.py
index 78ec780..fdfcad3 100644
--- a/src/beeper_desktop_api/types/__init__.py
+++ b/src/beeper_desktop_api/types/__init__.py
@@ -3,7 +3,14 @@
from __future__ import annotations
from .chat import Chat as Chat
-from .shared import User as User, Error as Error, Message as Message, Reaction as Reaction, Attachment as Attachment
+from .shared import (
+ User as User,
+ Error as Error,
+ Message as Message,
+ Reaction as Reaction,
+ Attachment as Attachment,
+ AppStateSnapshot as AppStateSnapshot,
+)
from .account import Account as Account
from .focus_response import FocusResponse as FocusResponse
from .search_response import SearchResponse as SearchResponse
@@ -14,12 +21,15 @@
from .chat_list_response import ChatListResponse as ChatListResponse
from .chat_search_params import ChatSearchParams as ChatSearchParams
from .chat_update_params import ChatUpdateParams as ChatUpdateParams
+from .app_status_response import AppStatusResponse as AppStatusResponse
from .asset_upload_params import AssetUploadParams as AssetUploadParams
+from .bridge_availability import BridgeAvailability as BridgeAvailability
from .chat_archive_params import ChatArchiveParams as ChatArchiveParams
from .chat_start_response import ChatStartResponse as ChatStartResponse
from .client_focus_params import ClientFocusParams as ClientFocusParams
from .message_list_params import MessageListParams as MessageListParams
from .message_send_params import MessageSendParams as MessageSendParams
+from .bridge_list_response import BridgeListResponse as BridgeListResponse
from .chat_create_response import ChatCreateResponse as ChatCreateResponse
from .chat_retrieve_params import ChatRetrieveParams as ChatRetrieveParams
from .client_search_params import ClientSearchParams as ClientSearchParams
diff --git a/src/beeper_desktop_api/types/app/__init__.py b/src/beeper_desktop_api/types/app/__init__.py
new file mode 100644
index 0000000..bf025a8
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/__init__.py
@@ -0,0 +1,10 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .login_email_params import LoginEmailParams as LoginEmailParams
+from .login_start_response import LoginStartResponse as LoginStartResponse
+from .login_register_params import LoginRegisterParams as LoginRegisterParams
+from .login_response_params import LoginResponseParams as LoginResponseParams
+from .login_register_response import LoginRegisterResponse as LoginRegisterResponse
+from .login_response_response import LoginResponseResponse as LoginResponseResponse
diff --git a/src/beeper_desktop_api/types/app/e2ee/__init__.py b/src/beeper_desktop_api/types/app/e2ee/__init__.py
new file mode 100644
index 0000000..2cd79cf
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/__init__.py
@@ -0,0 +1,12 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .verification_cancel_params import VerificationCancelParams as VerificationCancelParams
+from .verification_create_params import VerificationCreateParams as VerificationCreateParams
+from .recovery_code_verify_params import RecoveryCodeVerifyParams as RecoveryCodeVerifyParams
+from .verification_accept_response import VerificationAcceptResponse as VerificationAcceptResponse
+from .verification_cancel_response import VerificationCancelResponse as VerificationCancelResponse
+from .verification_create_response import VerificationCreateResponse as VerificationCreateResponse
+from .recovery_code_verify_response import RecoveryCodeVerifyResponse as RecoveryCodeVerifyResponse
+from .recovery_code_mark_backed_up_response import RecoveryCodeMarkBackedUpResponse as RecoveryCodeMarkBackedUpResponse
diff --git a/src/beeper_desktop_api/types/app/e2ee/recovery_code/__init__.py b/src/beeper_desktop_api/types/app/e2ee/recovery_code/__init__.py
new file mode 100644
index 0000000..0299c46
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/recovery_code/__init__.py
@@ -0,0 +1,8 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .reset_create_params import ResetCreateParams as ResetCreateParams
+from .reset_confirm_params import ResetConfirmParams as ResetConfirmParams
+from .reset_create_response import ResetCreateResponse as ResetCreateResponse
+from .reset_confirm_response import ResetConfirmResponse as ResetConfirmResponse
diff --git a/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_confirm_params.py b/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_confirm_params.py
new file mode 100644
index 0000000..745927e
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_confirm_params.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ....._utils import PropertyInfo
+
+__all__ = ["ResetConfirmParams"]
+
+
+class ResetConfirmParams(TypedDict, total=False):
+ recovery_code: Required[Annotated[str, PropertyInfo(alias="recoveryCode")]]
+ """New recovery key returned by the reset step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_confirm_response.py b/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_confirm_response.py
new file mode 100644
index 0000000..9ba8280
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_confirm_response.py
@@ -0,0 +1,170 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ....._models import BaseModel
+
+__all__ = [
+ "ResetConfirmResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after the requested step."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class ResetConfirmResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after the requested step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_create_params.py b/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_create_params.py
new file mode 100644
index 0000000..05928a2
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_create_params.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from ....._utils import PropertyInfo
+
+__all__ = ["ResetCreateParams"]
+
+
+class ResetCreateParams(TypedDict, total=False):
+ recovery_code: Annotated[str, PropertyInfo(alias="recoveryCode")]
+ """Existing recovery key, if the user has it."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_create_response.py b/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_create_response.py
new file mode 100644
index 0000000..8efd2b0
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/recovery_code/reset_create_response.py
@@ -0,0 +1,173 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ....._models import BaseModel
+
+__all__ = [
+ "ResetCreateResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after creating the new recovery key."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class ResetCreateResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after creating the new recovery key."""
+
+ recovery_code: str = FieldInfo(alias="recoveryCode")
+ """New recovery key. Show it once and ask the user to save it."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/recovery_code_mark_backed_up_response.py b/src/beeper_desktop_api/types/app/e2ee/recovery_code_mark_backed_up_response.py
new file mode 100644
index 0000000..a9b8f1d
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/recovery_code_mark_backed_up_response.py
@@ -0,0 +1,170 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ...._models import BaseModel
+
+__all__ = [
+ "RecoveryCodeMarkBackedUpResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after the requested step."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class RecoveryCodeMarkBackedUpResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after the requested step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/recovery_code_verify_params.py b/src/beeper_desktop_api/types/app/e2ee/recovery_code_verify_params.py
new file mode 100644
index 0000000..9869a2d
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/recovery_code_verify_params.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["RecoveryCodeVerifyParams"]
+
+
+class RecoveryCodeVerifyParams(TypedDict, total=False):
+ recovery_code: Required[Annotated[str, PropertyInfo(alias="recoveryCode")]]
+ """Recovery key saved by the user."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/recovery_code_verify_response.py b/src/beeper_desktop_api/types/app/e2ee/recovery_code_verify_response.py
new file mode 100644
index 0000000..4af7794
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/recovery_code_verify_response.py
@@ -0,0 +1,170 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ...._models import BaseModel
+
+__all__ = [
+ "RecoveryCodeVerifyResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after the requested step."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class RecoveryCodeVerifyResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after the requested step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification/__init__.py b/src/beeper_desktop_api/types/app/e2ee/verification/__init__.py
new file mode 100644
index 0000000..d0eff7c
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification/__init__.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .qr_scan_params import QrScanParams as QrScanParams
+from .qr_scan_response import QrScanResponse as QrScanResponse
+from .sa_start_response import SaStartResponse as SaStartResponse
+from .sa_confirm_response import SaConfirmResponse as SaConfirmResponse
+from .qr_confirm_scanned_response import QrConfirmScannedResponse as QrConfirmScannedResponse
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification/qr_confirm_scanned_response.py b/src/beeper_desktop_api/types/app/e2ee/verification/qr_confirm_scanned_response.py
new file mode 100644
index 0000000..a2032d8
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification/qr_confirm_scanned_response.py
@@ -0,0 +1,170 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ....._models import BaseModel
+
+__all__ = [
+ "QrConfirmScannedResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after the requested step."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class QrConfirmScannedResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after the requested step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification/qr_scan_params.py b/src/beeper_desktop_api/types/app/e2ee/verification/qr_scan_params.py
new file mode 100644
index 0000000..a16f78e
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification/qr_scan_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__ = ["QrScanParams"]
+
+
+class QrScanParams(TypedDict, total=False):
+ data: Required[str]
+ """QR code payload scanned from the other device."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification/qr_scan_response.py b/src/beeper_desktop_api/types/app/e2ee/verification/qr_scan_response.py
new file mode 100644
index 0000000..ef7014b
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification/qr_scan_response.py
@@ -0,0 +1,170 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ....._models import BaseModel
+
+__all__ = [
+ "QrScanResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after the requested step."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class QrScanResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after the requested step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification/sa_confirm_response.py b/src/beeper_desktop_api/types/app/e2ee/verification/sa_confirm_response.py
new file mode 100644
index 0000000..9f90136
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification/sa_confirm_response.py
@@ -0,0 +1,170 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ....._models import BaseModel
+
+__all__ = [
+ "SaConfirmResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after the requested step."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class SaConfirmResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after the requested step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification/sa_start_response.py b/src/beeper_desktop_api/types/app/e2ee/verification/sa_start_response.py
new file mode 100644
index 0000000..b68ed95
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification/sa_start_response.py
@@ -0,0 +1,170 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ....._models import BaseModel
+
+__all__ = [
+ "SaStartResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after the requested step."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class SaStartResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after the requested step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification_accept_response.py b/src/beeper_desktop_api/types/app/e2ee/verification_accept_response.py
new file mode 100644
index 0000000..5e3cc0e
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification_accept_response.py
@@ -0,0 +1,170 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ...._models import BaseModel
+
+__all__ = [
+ "VerificationAcceptResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after the requested step."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class VerificationAcceptResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after the requested step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification_cancel_params.py b/src/beeper_desktop_api/types/app/e2ee/verification_cancel_params.py
new file mode 100644
index 0000000..d954b97
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification_cancel_params.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__ = ["VerificationCancelParams"]
+
+
+class VerificationCancelParams(TypedDict, total=False):
+ code: str
+ """Optional cancellation code."""
+
+ reason: str
+ """Optional user-facing cancellation reason."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification_cancel_response.py b/src/beeper_desktop_api/types/app/e2ee/verification_cancel_response.py
new file mode 100644
index 0000000..4f19689
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification_cancel_response.py
@@ -0,0 +1,170 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ...._models import BaseModel
+
+__all__ = [
+ "VerificationCancelResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after the requested step."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class VerificationCancelResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after the requested step."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification_create_params.py b/src/beeper_desktop_api/types/app/e2ee/verification_create_params.py
new file mode 100644
index 0000000..c46feac
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification_create_params.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["VerificationCreateParams"]
+
+
+class VerificationCreateParams(TypedDict, total=False):
+ user_id: Annotated[str, PropertyInfo(alias="userID")]
+ """User ID to verify. Defaults to the signed-in user."""
diff --git a/src/beeper_desktop_api/types/app/e2ee/verification_create_response.py b/src/beeper_desktop_api/types/app/e2ee/verification_create_response.py
new file mode 100644
index 0000000..d5ccc58
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/e2ee/verification_create_response.py
@@ -0,0 +1,173 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ...._models import BaseModel
+
+__all__ = [
+ "VerificationCreateResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after starting verification."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class VerificationCreateResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after starting verification."""
+
+ verification_id: str = FieldInfo(alias="verificationID")
+ """Verification ID to pass in verification action paths."""
diff --git a/src/beeper_desktop_api/types/app/login_email_params.py b/src/beeper_desktop_api/types/app/login_email_params.py
new file mode 100644
index 0000000..bbf1d19
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/login_email_params.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 Required, TypedDict
+
+__all__ = ["LoginEmailParams"]
+
+
+class LoginEmailParams(TypedDict, total=False):
+ email: Required[str]
+ """Email address to send the sign-in code to."""
+
+ request: Required[str]
+ """Login request ID returned by the start step."""
diff --git a/src/beeper_desktop_api/types/app/login_register_params.py b/src/beeper_desktop_api/types/app/login_register_params.py
new file mode 100644
index 0000000..f6ea523
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/login_register_params.py
@@ -0,0 +1,26 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["LoginRegisterParams"]
+
+
+class LoginRegisterParams(TypedDict, total=False):
+ accept_terms: Required[Annotated[Literal[True], PropertyInfo(alias="acceptTerms")]]
+ """
+ Confirms that the user accepted the Terms of Use and acknowledged the Privacy
+ Policy.
+ """
+
+ lead_token: Required[Annotated[str, PropertyInfo(alias="leadToken")]]
+ """Registration token returned by Beeper."""
+
+ request: Required[str]
+ """Login request ID returned by the start step."""
+
+ username: Required[str]
+ """Username selected by the user."""
diff --git a/src/beeper_desktop_api/types/app/login_register_response.py b/src/beeper_desktop_api/types/app/login_register_response.py
new file mode 100644
index 0000000..1296355
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/login_register_response.py
@@ -0,0 +1,207 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = [
+ "LoginRegisterResponse",
+ "AppState",
+ "AppStateE2ee",
+ "AppStateE2eeSecrets",
+ "AppStateMatrix",
+ "AppStateVerification",
+ "AppStateVerificationError",
+ "AppStateVerificationSas",
+ "DesktopAPI",
+ "Matrix",
+]
+
+
+class AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppState(BaseModel):
+ """Current onboarding state after sign-in."""
+
+ e2ee: AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class DesktopAPI(BaseModel):
+ """Desktop API credentials for the signed-in app session."""
+
+ access_token: str = FieldInfo(alias="accessToken")
+ """Desktop API access token for this app session."""
+
+ scope: Literal["read write"]
+ """Granted Desktop API scopes."""
+
+ token_type: Literal["Bearer"] = FieldInfo(alias="tokenType")
+ """Access token type."""
+
+
+class Matrix(BaseModel):
+ """Account credentials for first-party app setup."""
+
+ access_token: str = FieldInfo(alias="accessToken")
+ """Account access token. Returned once for first-party app setup."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class LoginRegisterResponse(BaseModel):
+ app_state: AppState = FieldInfo(alias="appState")
+ """Current onboarding state after sign-in."""
+
+ desktop_api: DesktopAPI = FieldInfo(alias="desktopAPI")
+ """Desktop API credentials for the signed-in app session."""
+
+ matrix: Matrix
+ """Account credentials for first-party app setup."""
diff --git a/src/beeper_desktop_api/types/app/login_response_params.py b/src/beeper_desktop_api/types/app/login_response_params.py
new file mode 100644
index 0000000..f218f96
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/login_response_params.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 Required, TypedDict
+
+__all__ = ["LoginResponseParams"]
+
+
+class LoginResponseParams(TypedDict, total=False):
+ request: Required[str]
+ """Login request ID returned by the start step."""
+
+ response: Required[str]
+ """Sign-in code from the user email."""
diff --git a/src/beeper_desktop_api/types/app/login_response_response.py b/src/beeper_desktop_api/types/app/login_response_response.py
new file mode 100644
index 0000000..e28b77d
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/login_response_response.py
@@ -0,0 +1,246 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from typing_extensions import Literal, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = [
+ "LoginResponseResponse",
+ "UnionMember0",
+ "UnionMember0AppState",
+ "UnionMember0AppStateE2ee",
+ "UnionMember0AppStateE2eeSecrets",
+ "UnionMember0AppStateMatrix",
+ "UnionMember0AppStateVerification",
+ "UnionMember0AppStateVerificationError",
+ "UnionMember0AppStateVerificationSas",
+ "UnionMember0DesktopAPI",
+ "UnionMember0Matrix",
+ "UnionMember1",
+ "UnionMember1Copy",
+]
+
+
+class UnionMember0AppStateE2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class UnionMember0AppStateE2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: UnionMember0AppStateE2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class UnionMember0AppStateMatrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class UnionMember0AppStateVerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class UnionMember0AppStateVerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class UnionMember0AppStateVerification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[UnionMember0AppStateVerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[UnionMember0AppStateVerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class UnionMember0AppState(BaseModel):
+ """Current onboarding state after sign-in."""
+
+ e2ee: UnionMember0AppStateE2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[UnionMember0AppStateMatrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[UnionMember0AppStateVerification] = None
+ """Trusted-device verification progress."""
+
+
+class UnionMember0DesktopAPI(BaseModel):
+ """Desktop API credentials for the signed-in app session."""
+
+ access_token: str = FieldInfo(alias="accessToken")
+ """Desktop API access token for this app session."""
+
+ scope: Literal["read write"]
+ """Granted Desktop API scopes."""
+
+ token_type: Literal["Bearer"] = FieldInfo(alias="tokenType")
+ """Access token type."""
+
+
+class UnionMember0Matrix(BaseModel):
+ """Account credentials for first-party app setup."""
+
+ access_token: str = FieldInfo(alias="accessToken")
+ """Account access token. Returned once for first-party app setup."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class UnionMember0(BaseModel):
+ app_state: UnionMember0AppState = FieldInfo(alias="appState")
+ """Current onboarding state after sign-in."""
+
+ desktop_api: UnionMember0DesktopAPI = FieldInfo(alias="desktopAPI")
+ """Desktop API credentials for the signed-in app session."""
+
+ matrix: UnionMember0Matrix
+ """Account credentials for first-party app setup."""
+
+
+class UnionMember1Copy(BaseModel):
+ """Copy to display during account creation."""
+
+ submit: Literal["Continue"]
+ """Submit button label."""
+
+ terms: Literal["By continuing, you agree to the Terms of Use and acknowledge the Privacy Policy."]
+ """Terms and privacy notice to show before account creation."""
+
+ title: Literal["Choose your username"]
+ """Title for the username step."""
+
+ username_placeholder: Literal["Username"] = FieldInfo(alias="usernamePlaceholder")
+ """Placeholder for the username field."""
+
+
+class UnionMember1(BaseModel):
+ copy_: UnionMember1Copy = FieldInfo(alias="copy")
+ """Copy to display during account creation."""
+
+ lead_token: str = FieldInfo(alias="leadToken")
+ """Registration token returned by Beeper."""
+
+ registration_required: Literal[True] = FieldInfo(alias="registrationRequired")
+ """Indicates that the user needs to create a Beeper account."""
+
+ request: str
+ """Login request ID to use when creating the account."""
+
+ username_suggestions: Optional[List[str]] = FieldInfo(alias="usernameSuggestions", default=None)
+ """Suggested usernames for the new account."""
+
+
+LoginResponseResponse: TypeAlias = Union[UnionMember0, UnionMember1]
diff --git a/src/beeper_desktop_api/types/app/login_start_response.py b/src/beeper_desktop_api/types/app/login_start_response.py
new file mode 100644
index 0000000..d108b0d
--- /dev/null
+++ b/src/beeper_desktop_api/types/app/login_start_response.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from ..._models import BaseModel
+
+__all__ = ["LoginStartResponse"]
+
+
+class LoginStartResponse(BaseModel):
+ request: str
+ """Login request ID to use in the next sign-in step."""
+
+ type: List[str]
+ """Available sign-in methods for this request."""
diff --git a/src/beeper_desktop_api/types/app_status_response.py b/src/beeper_desktop_api/types/app_status_response.py
new file mode 100644
index 0000000..dbc8499
--- /dev/null
+++ b/src/beeper_desktop_api/types/app_status_response.py
@@ -0,0 +1,154 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["AppStatusResponse", "E2ee", "E2eeSecrets", "Matrix", "Verification", "VerificationError", "VerificationSas"]
+
+
+class E2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class E2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: E2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class Matrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class VerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class VerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class Verification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[VerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[VerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppStatusResponse(BaseModel):
+ e2ee: E2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[Matrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[Verification] = None
+ """Trusted-device verification progress."""
diff --git a/src/beeper_desktop_api/types/bridge_availability.py b/src/beeper_desktop_api/types/bridge_availability.py
new file mode 100644
index 0000000..abf7746
--- /dev/null
+++ b/src/beeper_desktop_api/types/bridge_availability.py
@@ -0,0 +1,63 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from .account import Account
+from .._models import BaseModel
+
+__all__ = ["BridgeAvailability", "Bridge"]
+
+
+class Bridge(BaseModel):
+ """Bridge metadata for the account. Available in Beeper Desktop v4.2.785+."""
+
+ id: str
+ """Bridge instance identifier.
+
+ Matrix and cloud bridges often use the bridge type (for example matrix or
+ discordgo); local bridges use a local bridge ID (for example local-whatsapp).
+ Available in Beeper Desktop v4.2.785+.
+ """
+
+ provider: Literal["cloud", "self-hosted", "local", "platform-sdk"]
+ """Bridge provider for the account. Available in Beeper Desktop v4.2.785+."""
+
+ type: str
+ """Bridge type, such as matrix, discordgo, slackgo, whatsapp, telegram, or twitter.
+
+ Available in Beeper Desktop v4.2.785+.
+ """
+
+
+class BridgeAvailability(BaseModel):
+ """Bridge-backed account type that can be shown in add-account flows."""
+
+ accounts: List[Account]
+ """Connected accounts for this bridge.
+
+ Uses the same Account schema as GET /v1/accounts.
+ """
+
+ active_account_count: int = FieldInfo(alias="activeAccountCount")
+ """Number of active accounts for this network on this device."""
+
+ bridge: Bridge
+ """Bridge metadata for the account. Available in Beeper Desktop v4.2.785+."""
+
+ display_name: str = FieldInfo(alias="displayName")
+ """Human-friendly account type name shown in Beeper Desktop."""
+
+ login_mode: str = FieldInfo(alias="loginMode")
+ """Login mode used by Beeper Desktop for this bridge."""
+
+ status: Literal["available", "connected", "limit_reached", "temporarily_unavailable"]
+ """Whether this bridge can currently be used to add an account."""
+
+ network: Optional[str] = None
+ """Network grouping used for account counts and limits."""
+
+ status_text: Optional[str] = FieldInfo(alias="statusText", default=None)
+ """Human-friendly status text matching Beeper Desktop account management language."""
diff --git a/src/beeper_desktop_api/types/bridge_list_response.py b/src/beeper_desktop_api/types/bridge_list_response.py
new file mode 100644
index 0000000..fc09661
--- /dev/null
+++ b/src/beeper_desktop_api/types/bridge_list_response.py
@@ -0,0 +1,14 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List
+
+from .._models import BaseModel
+from .bridge_availability import BridgeAvailability
+
+__all__ = ["BridgeListResponse"]
+
+
+class BridgeListResponse(BaseModel):
+ """Bridge-backed account types and their connected accounts."""
+
+ items: List[BridgeAvailability]
diff --git a/src/beeper_desktop_api/types/matrix/__init__.py b/src/beeper_desktop_api/types/matrix/__init__.py
new file mode 100644
index 0000000..1dfecfe
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/__init__.py
@@ -0,0 +1,10 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .room_join_params import RoomJoinParams as RoomJoinParams
+from .room_leave_params import RoomLeaveParams as RoomLeaveParams
+from .room_create_params import RoomCreateParams as RoomCreateParams
+from .room_join_response import RoomJoinResponse as RoomJoinResponse
+from .room_create_response import RoomCreateResponse as RoomCreateResponse
+from .user_retrieve_profile_response import UserRetrieveProfileResponse as UserRetrieveProfileResponse
diff --git a/src/beeper_desktop_api/types/matrix/bridges/__init__.py b/src/beeper_desktop_api/types/matrix/bridges/__init__.py
new file mode 100644
index 0000000..ff6da5f
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/__init__.py
@@ -0,0 +1,25 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .user_search_params import UserSearchParams as UserSearchParams
+from .contact_list_params import ContactListParams as ContactListParams
+from .user_resolve_params import UserResolveParams as UserResolveParams
+from .auth_whoami_response import AuthWhoamiResponse as AuthWhoamiResponse
+from .user_search_response import UserSearchResponse as UserSearchResponse
+from .contact_list_response import ContactListResponse as ContactListResponse
+from .room_create_dm_params import RoomCreateDmParams as RoomCreateDmParams
+from .user_resolve_response import UserResolveResponse as UserResolveResponse
+from .auth_start_login_params import AuthStartLoginParams as AuthStartLoginParams
+from .room_create_dm_response import RoomCreateDmResponse as RoomCreateDmResponse
+from .auth_list_flows_response import AuthListFlowsResponse as AuthListFlowsResponse
+from .room_create_group_params import RoomCreateGroupParams as RoomCreateGroupParams
+from .auth_list_logins_response import AuthListLoginsResponse as AuthListLoginsResponse
+from .auth_start_login_response import AuthStartLoginResponse as AuthStartLoginResponse
+from .auth_submit_cookies_params import AuthSubmitCookiesParams as AuthSubmitCookiesParams
+from .room_create_group_response import RoomCreateGroupResponse as RoomCreateGroupResponse
+from .auth_wait_for_step_response import AuthWaitForStepResponse as AuthWaitForStepResponse
+from .auth_submit_cookies_response import AuthSubmitCookiesResponse as AuthSubmitCookiesResponse
+from .capability_retrieve_response import CapabilityRetrieveResponse as CapabilityRetrieveResponse
+from .auth_submit_user_input_params import AuthSubmitUserInputParams as AuthSubmitUserInputParams
+from .auth_submit_user_input_response import AuthSubmitUserInputResponse as AuthSubmitUserInputResponse
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_list_flows_response.py b/src/beeper_desktop_api/types/matrix/bridges/auth_list_flows_response.py
new file mode 100644
index 0000000..05de99c
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_list_flows_response.py
@@ -0,0 +1,27 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from ...._models import BaseModel
+
+__all__ = ["AuthListFlowsResponse", "Flow"]
+
+
+class Flow(BaseModel):
+ """An individual login flow which can be used to sign into the remote network."""
+
+ id: str
+ """
+ An internal ID that is passed to the /login/start call to start a login with
+ this flow.
+ """
+
+ description: str
+ """A human-readable description of the login flow."""
+
+ name: str
+ """A human-readable name for the login flow."""
+
+
+class AuthListFlowsResponse(BaseModel):
+ flows: Optional[List[Flow]] = None
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_list_logins_response.py b/src/beeper_desktop_api/types/matrix/bridges/auth_list_logins_response.py
new file mode 100644
index 0000000..a0e9d3a
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_list_logins_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from ...._models import BaseModel
+
+__all__ = ["AuthListLoginsResponse"]
+
+
+class AuthListLoginsResponse(BaseModel):
+ login_ids: Optional[List[str]] = None
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_start_login_params.py b/src/beeper_desktop_api/types/matrix/bridges/auth_start_login_params.py
new file mode 100644
index 0000000..83368eb
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_start_login_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, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["AuthStartLoginParams"]
+
+
+class AuthStartLoginParams(TypedDict, total=False):
+ bridge_id: Required[Annotated[str, PropertyInfo(alias="bridgeID")]]
+
+ login_id: str
+ """An existing login ID to re-login as.
+
+ If this is specified and the user logs into a different account, the provided ID
+ will be logged out.
+ """
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_start_login_response.py b/src/beeper_desktop_api/types/matrix/bridges/auth_start_login_response.py
new file mode 100644
index 0000000..a63c5d6
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_start_login_response.py
@@ -0,0 +1,278 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from typing_extensions import Literal, TypeAlias
+
+from ...._models import BaseModel
+
+__all__ = [
+ "AuthStartLoginResponse",
+ "UnionMember0",
+ "UnionMember0DisplayAndWait",
+ "UnionMember1",
+ "UnionMember1UserInput",
+ "UnionMember1UserInputField",
+ "UnionMember1UserInputAttachment",
+ "UnionMember1UserInputAttachmentInfo",
+ "UnionMember2",
+ "UnionMember2Cookies",
+ "UnionMember2CookiesField",
+ "UnionMember3",
+ "UnionMember3Complete",
+]
+
+
+class UnionMember0DisplayAndWait(BaseModel):
+ """Parameters for the display and wait login step"""
+
+ type: Literal["qr", "emoji", "code", "nothing"]
+ """The type of thing to display"""
+
+ data: Optional[str] = None
+ """
+ The thing to display (raw data for QR, unicode emoji for emoji, plain string for
+ code)
+ """
+
+ image_url: Optional[str] = None
+ """An image containing the thing to display.
+
+ If present, this is recommended over using data directly. For emojis, the URL to
+ the canonical image representation of the emoji
+ """
+
+
+class UnionMember0(BaseModel):
+ """Display and wait login step"""
+
+ display_and_wait: UnionMember0DisplayAndWait
+ """Parameters for the display and wait login step"""
+
+ type: Literal["display_and_wait"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember1UserInputField(BaseModel):
+ """A field that the user can fill."""
+
+ id: str
+ """The internal ID of the field.
+
+ This must be used as the key in the object when submitting the data back to the
+ bridge.
+ """
+
+ name: str
+ """The name of the field shown to the user."""
+
+ type: Literal["username", "phone_number", "email", "password", "2fa_code", "token", "url", "domain", "select"]
+ """The type of field."""
+
+ default_value: Optional[str] = None
+ """A default value that the client can pre-fill the field with."""
+
+ description: Optional[str] = None
+ """A more detailed description of the field shown to the user."""
+
+ options: Optional[List[str]] = None
+ """For fields of type select, the valid options."""
+
+ pattern: Optional[str] = None
+ """A regular expression that the field value must match."""
+
+
+class UnionMember1UserInputAttachmentInfo(BaseModel):
+ """Optional but recommended metadata for the attachment.
+
+ Can generally be derived from the raw content if omitted.
+ """
+
+ h: Optional[float] = None
+ """The height of the media in pixels. Only applicable for images and videos."""
+
+ mimetype: Optional[str] = None
+ """The MIME type for the media content."""
+
+ size: Optional[float] = None
+ """The size of the media content in number of bytes.
+
+ Strongly recommended to include.
+ """
+
+ w: Optional[float] = None
+ """The width of the media in pixels. Only applicable for images and videos."""
+
+
+class UnionMember1UserInputAttachment(BaseModel):
+ """A media attachment to show the user."""
+
+ content: str
+ """The raw file content for the attachment encoded in base64."""
+
+ filename: str
+ """The filename for the media attachment."""
+
+ type: Literal["m.image", "m.audio"]
+ """
+ The type of media attachment, using the same media type identifiers as Matrix
+ attachments. Only some are supported.
+ """
+
+ info: Optional[UnionMember1UserInputAttachmentInfo] = None
+ """Optional but recommended metadata for the attachment.
+
+ Can generally be derived from the raw content if omitted.
+ """
+
+
+class UnionMember1UserInput(BaseModel):
+ """Parameters for the user input login step"""
+
+ fields: List[UnionMember1UserInputField]
+ """The list of fields that the user is requested to fill."""
+
+ attachments: Optional[List[UnionMember1UserInputAttachment]] = None
+ """A list of media attachments to show the user alongside the form fields."""
+
+
+class UnionMember1(BaseModel):
+ """User input login step"""
+
+ type: Literal["user_input"]
+
+ user_input: UnionMember1UserInput
+ """Parameters for the user input login step"""
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember2CookiesField(BaseModel):
+ """An individual cookie or other stored data item that must be extracted."""
+
+ name: str
+ """The name of the item to extract."""
+
+ type: Literal["cookie", "local_storage", "request_header", "request_body", "special"]
+ """The type of data to extract."""
+
+ cookie_domain: Optional[str] = None
+ """For the `cookie` type, the domain of the cookie."""
+
+ request_url_regex: Optional[str] = None
+ """
+ For the `request_header` and `request_body` types, a regex that matches the URLs
+ from which the values can be extracted.
+ """
+
+
+class UnionMember2Cookies(BaseModel):
+ """Parameters for the cookie login step"""
+
+ fields: List[UnionMember2CookiesField]
+ """The list of cookies or other stored data that must be extracted."""
+
+ url: str
+ """The URL to open when using a webview to extract cookies."""
+
+ extract_js: Optional[str] = None
+ """
+ A JavaScript snippet that can extract some or all of the fields. The snippet
+ will evaluate to a promise that resolves when the relevant fields are found.
+ Fields that are not present in the promise result must be extracted another way.
+ """
+
+ user_agent: Optional[str] = None
+ """An optional user agent that the webview should use."""
+
+ wait_for_url_pattern: Optional[str] = None
+ """A regex pattern that the URL should match before the client closes the webview.
+
+ The client may submit the login if the user closes the webview after all cookies
+ are collected even if this URL is not reached, but it should only automatically
+ close the webview after both cookies and the URL match.
+ """
+
+
+class UnionMember2(BaseModel):
+ """Cookie login step"""
+
+ cookies: UnionMember2Cookies
+ """Parameters for the cookie login step"""
+
+ type: Literal["cookies"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember3Complete(BaseModel):
+ """Information about the completed login"""
+
+ user_login_id: Optional[str] = None
+ """The unique ID of a login. Defined by the network connector."""
+
+
+class UnionMember3(BaseModel):
+ """Login complete"""
+
+ complete: UnionMember3Complete
+ """Information about the completed login"""
+
+ type: Literal["complete"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+AuthStartLoginResponse: TypeAlias = Union[UnionMember0, UnionMember1, UnionMember2, UnionMember3]
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_submit_cookies_params.py b/src/beeper_desktop_api/types/matrix/bridges/auth_submit_cookies_params.py
new file mode 100644
index 0000000..21a5979
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_submit_cookies_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict
+from typing_extensions import Required, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["AuthSubmitCookiesParams"]
+
+
+class AuthSubmitCookiesParams(TypedDict, total=False):
+ bridge_id: Required[Annotated[str, PropertyInfo(alias="bridgeID")]]
+
+ login_process_id: Required[Annotated[str, PropertyInfo(alias="loginProcessID")]]
+
+ body: Required[Dict[str, str]]
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_submit_cookies_response.py b/src/beeper_desktop_api/types/matrix/bridges/auth_submit_cookies_response.py
new file mode 100644
index 0000000..a4c0ce0
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_submit_cookies_response.py
@@ -0,0 +1,278 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from typing_extensions import Literal, TypeAlias
+
+from ...._models import BaseModel
+
+__all__ = [
+ "AuthSubmitCookiesResponse",
+ "UnionMember0",
+ "UnionMember0DisplayAndWait",
+ "UnionMember1",
+ "UnionMember1UserInput",
+ "UnionMember1UserInputField",
+ "UnionMember1UserInputAttachment",
+ "UnionMember1UserInputAttachmentInfo",
+ "UnionMember2",
+ "UnionMember2Cookies",
+ "UnionMember2CookiesField",
+ "UnionMember3",
+ "UnionMember3Complete",
+]
+
+
+class UnionMember0DisplayAndWait(BaseModel):
+ """Parameters for the display and wait login step"""
+
+ type: Literal["qr", "emoji", "code", "nothing"]
+ """The type of thing to display"""
+
+ data: Optional[str] = None
+ """
+ The thing to display (raw data for QR, unicode emoji for emoji, plain string for
+ code)
+ """
+
+ image_url: Optional[str] = None
+ """An image containing the thing to display.
+
+ If present, this is recommended over using data directly. For emojis, the URL to
+ the canonical image representation of the emoji
+ """
+
+
+class UnionMember0(BaseModel):
+ """Display and wait login step"""
+
+ display_and_wait: UnionMember0DisplayAndWait
+ """Parameters for the display and wait login step"""
+
+ type: Literal["display_and_wait"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember1UserInputField(BaseModel):
+ """A field that the user can fill."""
+
+ id: str
+ """The internal ID of the field.
+
+ This must be used as the key in the object when submitting the data back to the
+ bridge.
+ """
+
+ name: str
+ """The name of the field shown to the user."""
+
+ type: Literal["username", "phone_number", "email", "password", "2fa_code", "token", "url", "domain", "select"]
+ """The type of field."""
+
+ default_value: Optional[str] = None
+ """A default value that the client can pre-fill the field with."""
+
+ description: Optional[str] = None
+ """A more detailed description of the field shown to the user."""
+
+ options: Optional[List[str]] = None
+ """For fields of type select, the valid options."""
+
+ pattern: Optional[str] = None
+ """A regular expression that the field value must match."""
+
+
+class UnionMember1UserInputAttachmentInfo(BaseModel):
+ """Optional but recommended metadata for the attachment.
+
+ Can generally be derived from the raw content if omitted.
+ """
+
+ h: Optional[float] = None
+ """The height of the media in pixels. Only applicable for images and videos."""
+
+ mimetype: Optional[str] = None
+ """The MIME type for the media content."""
+
+ size: Optional[float] = None
+ """The size of the media content in number of bytes.
+
+ Strongly recommended to include.
+ """
+
+ w: Optional[float] = None
+ """The width of the media in pixels. Only applicable for images and videos."""
+
+
+class UnionMember1UserInputAttachment(BaseModel):
+ """A media attachment to show the user."""
+
+ content: str
+ """The raw file content for the attachment encoded in base64."""
+
+ filename: str
+ """The filename for the media attachment."""
+
+ type: Literal["m.image", "m.audio"]
+ """
+ The type of media attachment, using the same media type identifiers as Matrix
+ attachments. Only some are supported.
+ """
+
+ info: Optional[UnionMember1UserInputAttachmentInfo] = None
+ """Optional but recommended metadata for the attachment.
+
+ Can generally be derived from the raw content if omitted.
+ """
+
+
+class UnionMember1UserInput(BaseModel):
+ """Parameters for the user input login step"""
+
+ fields: List[UnionMember1UserInputField]
+ """The list of fields that the user is requested to fill."""
+
+ attachments: Optional[List[UnionMember1UserInputAttachment]] = None
+ """A list of media attachments to show the user alongside the form fields."""
+
+
+class UnionMember1(BaseModel):
+ """User input login step"""
+
+ type: Literal["user_input"]
+
+ user_input: UnionMember1UserInput
+ """Parameters for the user input login step"""
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember2CookiesField(BaseModel):
+ """An individual cookie or other stored data item that must be extracted."""
+
+ name: str
+ """The name of the item to extract."""
+
+ type: Literal["cookie", "local_storage", "request_header", "request_body", "special"]
+ """The type of data to extract."""
+
+ cookie_domain: Optional[str] = None
+ """For the `cookie` type, the domain of the cookie."""
+
+ request_url_regex: Optional[str] = None
+ """
+ For the `request_header` and `request_body` types, a regex that matches the URLs
+ from which the values can be extracted.
+ """
+
+
+class UnionMember2Cookies(BaseModel):
+ """Parameters for the cookie login step"""
+
+ fields: List[UnionMember2CookiesField]
+ """The list of cookies or other stored data that must be extracted."""
+
+ url: str
+ """The URL to open when using a webview to extract cookies."""
+
+ extract_js: Optional[str] = None
+ """
+ A JavaScript snippet that can extract some or all of the fields. The snippet
+ will evaluate to a promise that resolves when the relevant fields are found.
+ Fields that are not present in the promise result must be extracted another way.
+ """
+
+ user_agent: Optional[str] = None
+ """An optional user agent that the webview should use."""
+
+ wait_for_url_pattern: Optional[str] = None
+ """A regex pattern that the URL should match before the client closes the webview.
+
+ The client may submit the login if the user closes the webview after all cookies
+ are collected even if this URL is not reached, but it should only automatically
+ close the webview after both cookies and the URL match.
+ """
+
+
+class UnionMember2(BaseModel):
+ """Cookie login step"""
+
+ cookies: UnionMember2Cookies
+ """Parameters for the cookie login step"""
+
+ type: Literal["cookies"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember3Complete(BaseModel):
+ """Information about the completed login"""
+
+ user_login_id: Optional[str] = None
+ """The unique ID of a login. Defined by the network connector."""
+
+
+class UnionMember3(BaseModel):
+ """Login complete"""
+
+ complete: UnionMember3Complete
+ """Information about the completed login"""
+
+ type: Literal["complete"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+AuthSubmitCookiesResponse: TypeAlias = Union[UnionMember0, UnionMember1, UnionMember2, UnionMember3]
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_submit_user_input_params.py b/src/beeper_desktop_api/types/matrix/bridges/auth_submit_user_input_params.py
new file mode 100644
index 0000000..edbb7db
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_submit_user_input_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict
+from typing_extensions import Required, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["AuthSubmitUserInputParams"]
+
+
+class AuthSubmitUserInputParams(TypedDict, total=False):
+ bridge_id: Required[Annotated[str, PropertyInfo(alias="bridgeID")]]
+
+ login_process_id: Required[Annotated[str, PropertyInfo(alias="loginProcessID")]]
+
+ body: Required[Dict[str, str]]
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_submit_user_input_response.py b/src/beeper_desktop_api/types/matrix/bridges/auth_submit_user_input_response.py
new file mode 100644
index 0000000..0f2808d
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_submit_user_input_response.py
@@ -0,0 +1,278 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from typing_extensions import Literal, TypeAlias
+
+from ...._models import BaseModel
+
+__all__ = [
+ "AuthSubmitUserInputResponse",
+ "UnionMember0",
+ "UnionMember0DisplayAndWait",
+ "UnionMember1",
+ "UnionMember1UserInput",
+ "UnionMember1UserInputField",
+ "UnionMember1UserInputAttachment",
+ "UnionMember1UserInputAttachmentInfo",
+ "UnionMember2",
+ "UnionMember2Cookies",
+ "UnionMember2CookiesField",
+ "UnionMember3",
+ "UnionMember3Complete",
+]
+
+
+class UnionMember0DisplayAndWait(BaseModel):
+ """Parameters for the display and wait login step"""
+
+ type: Literal["qr", "emoji", "code", "nothing"]
+ """The type of thing to display"""
+
+ data: Optional[str] = None
+ """
+ The thing to display (raw data for QR, unicode emoji for emoji, plain string for
+ code)
+ """
+
+ image_url: Optional[str] = None
+ """An image containing the thing to display.
+
+ If present, this is recommended over using data directly. For emojis, the URL to
+ the canonical image representation of the emoji
+ """
+
+
+class UnionMember0(BaseModel):
+ """Display and wait login step"""
+
+ display_and_wait: UnionMember0DisplayAndWait
+ """Parameters for the display and wait login step"""
+
+ type: Literal["display_and_wait"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember1UserInputField(BaseModel):
+ """A field that the user can fill."""
+
+ id: str
+ """The internal ID of the field.
+
+ This must be used as the key in the object when submitting the data back to the
+ bridge.
+ """
+
+ name: str
+ """The name of the field shown to the user."""
+
+ type: Literal["username", "phone_number", "email", "password", "2fa_code", "token", "url", "domain", "select"]
+ """The type of field."""
+
+ default_value: Optional[str] = None
+ """A default value that the client can pre-fill the field with."""
+
+ description: Optional[str] = None
+ """A more detailed description of the field shown to the user."""
+
+ options: Optional[List[str]] = None
+ """For fields of type select, the valid options."""
+
+ pattern: Optional[str] = None
+ """A regular expression that the field value must match."""
+
+
+class UnionMember1UserInputAttachmentInfo(BaseModel):
+ """Optional but recommended metadata for the attachment.
+
+ Can generally be derived from the raw content if omitted.
+ """
+
+ h: Optional[float] = None
+ """The height of the media in pixels. Only applicable for images and videos."""
+
+ mimetype: Optional[str] = None
+ """The MIME type for the media content."""
+
+ size: Optional[float] = None
+ """The size of the media content in number of bytes.
+
+ Strongly recommended to include.
+ """
+
+ w: Optional[float] = None
+ """The width of the media in pixels. Only applicable for images and videos."""
+
+
+class UnionMember1UserInputAttachment(BaseModel):
+ """A media attachment to show the user."""
+
+ content: str
+ """The raw file content for the attachment encoded in base64."""
+
+ filename: str
+ """The filename for the media attachment."""
+
+ type: Literal["m.image", "m.audio"]
+ """
+ The type of media attachment, using the same media type identifiers as Matrix
+ attachments. Only some are supported.
+ """
+
+ info: Optional[UnionMember1UserInputAttachmentInfo] = None
+ """Optional but recommended metadata for the attachment.
+
+ Can generally be derived from the raw content if omitted.
+ """
+
+
+class UnionMember1UserInput(BaseModel):
+ """Parameters for the user input login step"""
+
+ fields: List[UnionMember1UserInputField]
+ """The list of fields that the user is requested to fill."""
+
+ attachments: Optional[List[UnionMember1UserInputAttachment]] = None
+ """A list of media attachments to show the user alongside the form fields."""
+
+
+class UnionMember1(BaseModel):
+ """User input login step"""
+
+ type: Literal["user_input"]
+
+ user_input: UnionMember1UserInput
+ """Parameters for the user input login step"""
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember2CookiesField(BaseModel):
+ """An individual cookie or other stored data item that must be extracted."""
+
+ name: str
+ """The name of the item to extract."""
+
+ type: Literal["cookie", "local_storage", "request_header", "request_body", "special"]
+ """The type of data to extract."""
+
+ cookie_domain: Optional[str] = None
+ """For the `cookie` type, the domain of the cookie."""
+
+ request_url_regex: Optional[str] = None
+ """
+ For the `request_header` and `request_body` types, a regex that matches the URLs
+ from which the values can be extracted.
+ """
+
+
+class UnionMember2Cookies(BaseModel):
+ """Parameters for the cookie login step"""
+
+ fields: List[UnionMember2CookiesField]
+ """The list of cookies or other stored data that must be extracted."""
+
+ url: str
+ """The URL to open when using a webview to extract cookies."""
+
+ extract_js: Optional[str] = None
+ """
+ A JavaScript snippet that can extract some or all of the fields. The snippet
+ will evaluate to a promise that resolves when the relevant fields are found.
+ Fields that are not present in the promise result must be extracted another way.
+ """
+
+ user_agent: Optional[str] = None
+ """An optional user agent that the webview should use."""
+
+ wait_for_url_pattern: Optional[str] = None
+ """A regex pattern that the URL should match before the client closes the webview.
+
+ The client may submit the login if the user closes the webview after all cookies
+ are collected even if this URL is not reached, but it should only automatically
+ close the webview after both cookies and the URL match.
+ """
+
+
+class UnionMember2(BaseModel):
+ """Cookie login step"""
+
+ cookies: UnionMember2Cookies
+ """Parameters for the cookie login step"""
+
+ type: Literal["cookies"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember3Complete(BaseModel):
+ """Information about the completed login"""
+
+ user_login_id: Optional[str] = None
+ """The unique ID of a login. Defined by the network connector."""
+
+
+class UnionMember3(BaseModel):
+ """Login complete"""
+
+ complete: UnionMember3Complete
+ """Information about the completed login"""
+
+ type: Literal["complete"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+AuthSubmitUserInputResponse: TypeAlias = Union[UnionMember0, UnionMember1, UnionMember2, UnionMember3]
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_wait_for_step_response.py b/src/beeper_desktop_api/types/matrix/bridges/auth_wait_for_step_response.py
new file mode 100644
index 0000000..bd2fb65
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_wait_for_step_response.py
@@ -0,0 +1,278 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from typing_extensions import Literal, TypeAlias
+
+from ...._models import BaseModel
+
+__all__ = [
+ "AuthWaitForStepResponse",
+ "UnionMember0",
+ "UnionMember0DisplayAndWait",
+ "UnionMember1",
+ "UnionMember1UserInput",
+ "UnionMember1UserInputField",
+ "UnionMember1UserInputAttachment",
+ "UnionMember1UserInputAttachmentInfo",
+ "UnionMember2",
+ "UnionMember2Cookies",
+ "UnionMember2CookiesField",
+ "UnionMember3",
+ "UnionMember3Complete",
+]
+
+
+class UnionMember0DisplayAndWait(BaseModel):
+ """Parameters for the display and wait login step"""
+
+ type: Literal["qr", "emoji", "code", "nothing"]
+ """The type of thing to display"""
+
+ data: Optional[str] = None
+ """
+ The thing to display (raw data for QR, unicode emoji for emoji, plain string for
+ code)
+ """
+
+ image_url: Optional[str] = None
+ """An image containing the thing to display.
+
+ If present, this is recommended over using data directly. For emojis, the URL to
+ the canonical image representation of the emoji
+ """
+
+
+class UnionMember0(BaseModel):
+ """Display and wait login step"""
+
+ display_and_wait: UnionMember0DisplayAndWait
+ """Parameters for the display and wait login step"""
+
+ type: Literal["display_and_wait"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember1UserInputField(BaseModel):
+ """A field that the user can fill."""
+
+ id: str
+ """The internal ID of the field.
+
+ This must be used as the key in the object when submitting the data back to the
+ bridge.
+ """
+
+ name: str
+ """The name of the field shown to the user."""
+
+ type: Literal["username", "phone_number", "email", "password", "2fa_code", "token", "url", "domain", "select"]
+ """The type of field."""
+
+ default_value: Optional[str] = None
+ """A default value that the client can pre-fill the field with."""
+
+ description: Optional[str] = None
+ """A more detailed description of the field shown to the user."""
+
+ options: Optional[List[str]] = None
+ """For fields of type select, the valid options."""
+
+ pattern: Optional[str] = None
+ """A regular expression that the field value must match."""
+
+
+class UnionMember1UserInputAttachmentInfo(BaseModel):
+ """Optional but recommended metadata for the attachment.
+
+ Can generally be derived from the raw content if omitted.
+ """
+
+ h: Optional[float] = None
+ """The height of the media in pixels. Only applicable for images and videos."""
+
+ mimetype: Optional[str] = None
+ """The MIME type for the media content."""
+
+ size: Optional[float] = None
+ """The size of the media content in number of bytes.
+
+ Strongly recommended to include.
+ """
+
+ w: Optional[float] = None
+ """The width of the media in pixels. Only applicable for images and videos."""
+
+
+class UnionMember1UserInputAttachment(BaseModel):
+ """A media attachment to show the user."""
+
+ content: str
+ """The raw file content for the attachment encoded in base64."""
+
+ filename: str
+ """The filename for the media attachment."""
+
+ type: Literal["m.image", "m.audio"]
+ """
+ The type of media attachment, using the same media type identifiers as Matrix
+ attachments. Only some are supported.
+ """
+
+ info: Optional[UnionMember1UserInputAttachmentInfo] = None
+ """Optional but recommended metadata for the attachment.
+
+ Can generally be derived from the raw content if omitted.
+ """
+
+
+class UnionMember1UserInput(BaseModel):
+ """Parameters for the user input login step"""
+
+ fields: List[UnionMember1UserInputField]
+ """The list of fields that the user is requested to fill."""
+
+ attachments: Optional[List[UnionMember1UserInputAttachment]] = None
+ """A list of media attachments to show the user alongside the form fields."""
+
+
+class UnionMember1(BaseModel):
+ """User input login step"""
+
+ type: Literal["user_input"]
+
+ user_input: UnionMember1UserInput
+ """Parameters for the user input login step"""
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember2CookiesField(BaseModel):
+ """An individual cookie or other stored data item that must be extracted."""
+
+ name: str
+ """The name of the item to extract."""
+
+ type: Literal["cookie", "local_storage", "request_header", "request_body", "special"]
+ """The type of data to extract."""
+
+ cookie_domain: Optional[str] = None
+ """For the `cookie` type, the domain of the cookie."""
+
+ request_url_regex: Optional[str] = None
+ """
+ For the `request_header` and `request_body` types, a regex that matches the URLs
+ from which the values can be extracted.
+ """
+
+
+class UnionMember2Cookies(BaseModel):
+ """Parameters for the cookie login step"""
+
+ fields: List[UnionMember2CookiesField]
+ """The list of cookies or other stored data that must be extracted."""
+
+ url: str
+ """The URL to open when using a webview to extract cookies."""
+
+ extract_js: Optional[str] = None
+ """
+ A JavaScript snippet that can extract some or all of the fields. The snippet
+ will evaluate to a promise that resolves when the relevant fields are found.
+ Fields that are not present in the promise result must be extracted another way.
+ """
+
+ user_agent: Optional[str] = None
+ """An optional user agent that the webview should use."""
+
+ wait_for_url_pattern: Optional[str] = None
+ """A regex pattern that the URL should match before the client closes the webview.
+
+ The client may submit the login if the user closes the webview after all cookies
+ are collected even if this URL is not reached, but it should only automatically
+ close the webview after both cookies and the URL match.
+ """
+
+
+class UnionMember2(BaseModel):
+ """Cookie login step"""
+
+ cookies: UnionMember2Cookies
+ """Parameters for the cookie login step"""
+
+ type: Literal["cookies"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+class UnionMember3Complete(BaseModel):
+ """Information about the completed login"""
+
+ user_login_id: Optional[str] = None
+ """The unique ID of a login. Defined by the network connector."""
+
+
+class UnionMember3(BaseModel):
+ """Login complete"""
+
+ complete: UnionMember3Complete
+ """Information about the completed login"""
+
+ type: Literal["complete"]
+
+ instructions: Optional[str] = None
+ """Human-readable instructions for completing this login step."""
+
+ login_id: Optional[str] = None
+ """An identifier for the current login process.
+
+ Must be passed to execute more steps of the login.
+ """
+
+ step_id: Optional[str] = None
+ """An unique ID identifying this step.
+
+ This can be used to implement special behavior in clients.
+ """
+
+
+AuthWaitForStepResponse: TypeAlias = Union[UnionMember0, UnionMember1, UnionMember2, UnionMember3]
diff --git a/src/beeper_desktop_api/types/matrix/bridges/auth_whoami_response.py b/src/beeper_desktop_api/types/matrix/bridges/auth_whoami_response.py
new file mode 100644
index 0000000..7bd7db7
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/auth_whoami_response.py
@@ -0,0 +1,128 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from ...._models import BaseModel
+
+__all__ = ["AuthWhoamiResponse", "LoginFlow", "Login", "LoginProfile", "LoginState", "Network"]
+
+
+class LoginFlow(BaseModel):
+ """An individual login flow which can be used to sign into the remote network."""
+
+ id: str
+ """
+ An internal ID that is passed to the /login/start call to start a login with
+ this flow.
+ """
+
+ description: str
+ """A human-readable description of the login flow."""
+
+ name: str
+ """A human-readable name for the login flow."""
+
+
+class LoginProfile(BaseModel):
+ """The profile info of the logged-in user on the remote network."""
+
+ avatar: Optional[str] = None
+ """The user's avatar"""
+
+ email: Optional[str] = None
+ """The user's email address"""
+
+ name: Optional[str] = None
+ """The user's displayname"""
+
+ phone: Optional[str] = None
+ """The user's phone number"""
+
+ username: Optional[str] = None
+ """The user's username"""
+
+
+class LoginState(BaseModel):
+ """The connection status of an individual login"""
+
+ state_event: Literal["CONNECTING", "CONNECTED", "TRANSIENT_DISCONNECT", "BAD_CREDENTIALS", "UNKNOWN_ERROR"]
+ """The current state of this login."""
+
+ timestamp: float
+ """The time when the state was last updated."""
+
+ error: Optional[str] = None
+ """An error code defined by the network connector."""
+
+ info: Optional[object] = None
+ """Additional arbitrary info provided by the network connector."""
+
+ message: Optional[str] = None
+ """A human-readable error message defined by the network connector."""
+
+ reason: Optional[str] = None
+ """A reason code for non-error states that aren't exactly successes either."""
+
+
+class Login(BaseModel):
+ """The info of an individual login"""
+
+ id: str
+ """The unique ID of a login. Defined by the network connector."""
+
+ name: str
+ """A human-readable name for the login. Defined by the network connector."""
+
+ profile: LoginProfile
+ """The profile info of the logged-in user on the remote network."""
+
+ state: LoginState
+ """The connection status of an individual login"""
+
+ space_room: Optional[str] = None
+ """The personal filtering space room ID for this login."""
+
+
+class Network(BaseModel):
+ """Info about the network that the bridge is bridging to."""
+
+ beeper_bridge_type: str
+ """An identifier uniquely identifying the bridge software."""
+
+ displayname: str
+ """The displayname of the network."""
+
+ network_icon: str
+ """The icon of the network as a `mxc://` URI."""
+
+ network_id: str
+ """An identifier uniquely identifying the network."""
+
+ network_url: str
+ """The URL to the website of the network."""
+
+
+class AuthWhoamiResponse(BaseModel):
+ """Info about the bridge and user"""
+
+ bridge_bot: str
+ """The Matrix user ID of the bridge bot."""
+
+ command_prefix: str
+ """The command prefix used by this bridge."""
+
+ homeserver: str
+ """The server name the bridge is running on."""
+
+ login_flows: List[LoginFlow]
+ """The login flows that the bridge supports."""
+
+ logins: List[Login]
+ """The logins of the user who made the /whoami call"""
+
+ network: Network
+ """Info about the network that the bridge is bridging to."""
+
+ management_room: Optional[str] = None
+ """The Matrix management room ID of the user who made the /whoami call."""
diff --git a/src/beeper_desktop_api/types/matrix/bridges/capability_retrieve_response.py b/src/beeper_desktop_api/types/matrix/bridges/capability_retrieve_response.py
new file mode 100644
index 0000000..18c6716
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/capability_retrieve_response.py
@@ -0,0 +1,8 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict
+from typing_extensions import TypeAlias
+
+__all__ = ["CapabilityRetrieveResponse"]
+
+CapabilityRetrieveResponse: TypeAlias = Dict[str, object]
diff --git a/src/beeper_desktop_api/types/matrix/bridges/contact_list_params.py b/src/beeper_desktop_api/types/matrix/bridges/contact_list_params.py
new file mode 100644
index 0000000..73465db
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/contact_list_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 TypedDict
+
+__all__ = ["ContactListParams"]
+
+
+class ContactListParams(TypedDict, total=False):
+ login_id: str
+ """An optional explicit login ID to do the action through."""
diff --git a/src/beeper_desktop_api/types/matrix/bridges/contact_list_response.py b/src/beeper_desktop_api/types/matrix/bridges/contact_list_response.py
new file mode 100644
index 0000000..c0b51dc
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/contact_list_response.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from ...._models import BaseModel
+
+__all__ = ["ContactListResponse", "Contact"]
+
+
+class Contact(BaseModel):
+ """A successfully resolved identifier."""
+
+ id: str
+ """The internal user ID of the resolved user."""
+
+ avatar_url: Optional[str] = None
+ """The avatar of the user on the remote network."""
+
+ dm_room_mxid: Optional[str] = None
+ """The Matrix room ID of the direct chat with the user."""
+
+ identifiers: Optional[List[str]] = None
+ """A list of identifiers for the user on the remote network."""
+
+ mxid: Optional[str] = None
+ """The Matrix user ID of the ghost representing the user."""
+
+ name: Optional[str] = None
+ """The name of the user on the remote network."""
+
+
+class ContactListResponse(BaseModel):
+ contacts: Optional[List[Contact]] = None
diff --git a/src/beeper_desktop_api/types/matrix/bridges/room_create_dm_params.py b/src/beeper_desktop_api/types/matrix/bridges/room_create_dm_params.py
new file mode 100644
index 0000000..5535a29
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/room_create_dm_params.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["RoomCreateDmParams"]
+
+
+class RoomCreateDmParams(TypedDict, total=False):
+ bridge_id: Required[Annotated[str, PropertyInfo(alias="bridgeID")]]
+
+ login_id: str
+ """An optional explicit login ID to do the action through."""
diff --git a/src/beeper_desktop_api/types/matrix/bridges/room_create_dm_response.py b/src/beeper_desktop_api/types/matrix/bridges/room_create_dm_response.py
new file mode 100644
index 0000000..f15debc
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/room_create_dm_response.py
@@ -0,0 +1,29 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from ...._models import BaseModel
+
+__all__ = ["RoomCreateDmResponse"]
+
+
+class RoomCreateDmResponse(BaseModel):
+ """A successfully resolved identifier."""
+
+ id: str
+ """The internal user ID of the resolved user."""
+
+ avatar_url: Optional[str] = None
+ """The avatar of the user on the remote network."""
+
+ dm_room_mxid: Optional[str] = None
+ """The Matrix room ID of the direct chat with the user."""
+
+ identifiers: Optional[List[str]] = None
+ """A list of identifiers for the user on the remote network."""
+
+ mxid: Optional[str] = None
+ """The Matrix user ID of the ghost representing the user."""
+
+ name: Optional[str] = None
+ """The name of the user on the remote network."""
diff --git a/src/beeper_desktop_api/types/matrix/bridges/room_create_group_params.py b/src/beeper_desktop_api/types/matrix/bridges/room_create_group_params.py
new file mode 100644
index 0000000..de9c10d
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/room_create_group_params.py
@@ -0,0 +1,72 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ...._types import SequenceNotStr
+from ...._utils import PropertyInfo
+
+__all__ = ["RoomCreateGroupParams", "Avatar", "Disappear", "Name", "Topic"]
+
+
+class RoomCreateGroupParams(TypedDict, total=False):
+ bridge_id: Required[Annotated[str, PropertyInfo(alias="bridgeID")]]
+
+ login_id: str
+ """An optional explicit login ID to do the action through."""
+
+ avatar: Avatar
+ """The `m.room.avatar` event content for the room."""
+
+ disappear: Disappear
+ """The `com.beeper.disappearing_timer` event content for the room."""
+
+ name: Name
+ """The `m.room.name` event content for the room."""
+
+ parent: object
+
+ participants: SequenceNotStr[str]
+ """The users to add to the group initially."""
+
+ room_id: str
+ """
+ An existing Matrix room ID to bridge to. The other parameters must be already in
+ sync with the room state when using this parameter.
+ """
+
+ topic: Topic
+ """The `m.room.topic` event content for the room."""
+
+ type: str
+ """The type of group to create."""
+
+ username: str
+ """The public username for the created group."""
+
+
+class Avatar(TypedDict, total=False):
+ """The `m.room.avatar` event content for the room."""
+
+ url: str
+
+
+class Disappear(TypedDict, total=False):
+ """The `com.beeper.disappearing_timer` event content for the room."""
+
+ timer: float
+
+ type: str
+
+
+class Name(TypedDict, total=False):
+ """The `m.room.name` event content for the room."""
+
+ name: str
+
+
+class Topic(TypedDict, total=False):
+ """The `m.room.topic` event content for the room."""
+
+ topic: str
diff --git a/src/beeper_desktop_api/types/matrix/bridges/room_create_group_response.py b/src/beeper_desktop_api/types/matrix/bridges/room_create_group_response.py
new file mode 100644
index 0000000..824275b
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/room_create_group_response.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from ...._models import BaseModel
+
+__all__ = ["RoomCreateGroupResponse"]
+
+
+class RoomCreateGroupResponse(BaseModel):
+ """A successfully created group chat."""
+
+ id: str
+ """The internal chat ID of the created group."""
+
+ mxid: str
+ """The Matrix room ID of the portal."""
diff --git a/src/beeper_desktop_api/types/matrix/bridges/user_resolve_params.py b/src/beeper_desktop_api/types/matrix/bridges/user_resolve_params.py
new file mode 100644
index 0000000..46d6b21
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/user_resolve_params.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["UserResolveParams"]
+
+
+class UserResolveParams(TypedDict, total=False):
+ bridge_id: Required[Annotated[str, PropertyInfo(alias="bridgeID")]]
+
+ login_id: str
+ """An optional explicit login ID to do the action through."""
diff --git a/src/beeper_desktop_api/types/matrix/bridges/user_resolve_response.py b/src/beeper_desktop_api/types/matrix/bridges/user_resolve_response.py
new file mode 100644
index 0000000..22b2517
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/user_resolve_response.py
@@ -0,0 +1,29 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from ...._models import BaseModel
+
+__all__ = ["UserResolveResponse"]
+
+
+class UserResolveResponse(BaseModel):
+ """A successfully resolved identifier."""
+
+ id: str
+ """The internal user ID of the resolved user."""
+
+ avatar_url: Optional[str] = None
+ """The avatar of the user on the remote network."""
+
+ dm_room_mxid: Optional[str] = None
+ """The Matrix room ID of the direct chat with the user."""
+
+ identifiers: Optional[List[str]] = None
+ """A list of identifiers for the user on the remote network."""
+
+ mxid: Optional[str] = None
+ """The Matrix user ID of the ghost representing the user."""
+
+ name: Optional[str] = None
+ """The name of the user on the remote network."""
diff --git a/src/beeper_desktop_api/types/matrix/bridges/user_search_params.py b/src/beeper_desktop_api/types/matrix/bridges/user_search_params.py
new file mode 100644
index 0000000..45190a8
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/user_search_params.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__ = ["UserSearchParams"]
+
+
+class UserSearchParams(TypedDict, total=False):
+ login_id: str
+ """An optional explicit login ID to do the action through."""
+
+ query: str
+ """The search query to send to the remote network"""
diff --git a/src/beeper_desktop_api/types/matrix/bridges/user_search_response.py b/src/beeper_desktop_api/types/matrix/bridges/user_search_response.py
new file mode 100644
index 0000000..c001e5c
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/bridges/user_search_response.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+
+from ...._models import BaseModel
+
+__all__ = ["UserSearchResponse", "Result"]
+
+
+class Result(BaseModel):
+ """A successfully resolved identifier."""
+
+ id: str
+ """The internal user ID of the resolved user."""
+
+ avatar_url: Optional[str] = None
+ """The avatar of the user on the remote network."""
+
+ dm_room_mxid: Optional[str] = None
+ """The Matrix room ID of the direct chat with the user."""
+
+ identifiers: Optional[List[str]] = None
+ """A list of identifiers for the user on the remote network."""
+
+ mxid: Optional[str] = None
+ """The Matrix user ID of the ghost representing the user."""
+
+ name: Optional[str] = None
+ """The name of the user on the remote network."""
+
+
+class UserSearchResponse(BaseModel):
+ results: Optional[List[Result]] = None
diff --git a/src/beeper_desktop_api/types/matrix/room_create_params.py b/src/beeper_desktop_api/types/matrix/room_create_params.py
new file mode 100644
index 0000000..073228e
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/room_create_params.py
@@ -0,0 +1,157 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable
+from typing_extensions import Literal, Required, TypedDict
+
+from ..._types import SequenceNotStr
+
+__all__ = ["RoomCreateParams", "InitialState", "Invite3pid"]
+
+
+class RoomCreateParams(TypedDict, total=False):
+ creation_content: object
+ """
+ Extra keys, such as `m.federate`, to be added to the content of the
+ [`m.room.create`](https://spec.matrix.org/v1.18/client-server-api/#mroomcreate)
+ event.
+
+ The server will overwrite the following keys: `creator`, `room_version`. Future
+ versions of the specification may allow the server to overwrite other keys.
+
+ When using the `trusted_private_chat` preset, the server SHOULD combine
+ `additional_creators` specified here and the `invite` array into the eventual
+ `m.room.create` event's `additional_creators`, deduplicating between the two
+ parameters.
+ """
+
+ initial_state: Iterable[InitialState]
+ """A list of state events to set in the new room.
+
+ This allows the user to override the default state events set in the new room.
+ The expected format of the state events are an object with type, state_key and
+ content keys set.
+
+ Takes precedence over events set by `preset`, but gets overridden by `name` and
+ `topic` keys.
+ """
+
+ invite: SequenceNotStr[str]
+ """A list of user IDs to invite to the room.
+
+ This will tell the server to invite everyone in the list to the newly created
+ room.
+ """
+
+ invite_3pid: Iterable[Invite3pid]
+ """A list of objects representing third-party IDs to invite into the room."""
+
+ is_direct: bool
+ """
+ This flag makes the server set the `is_direct` flag on the `m.room.member`
+ events sent to the users in `invite` and `invite_3pid`. See
+ [Direct Messaging](https://spec.matrix.org/v1.18/client-server-api/#direct-messaging)
+ for more information.
+ """
+
+ name: str
+ """
+ If this is included, an
+ [`m.room.name`](https://spec.matrix.org/v1.18/client-server-api/#mroomname)
+ event will be sent into the room to indicate the name for the room. This
+ overwrites any
+ [`m.room.name`](https://spec.matrix.org/v1.18/client-server-api/#mroomname)
+ event in `initial_state`.
+ """
+
+ power_level_content_override: object
+ """The power level content to override in the default power level event.
+
+ This object is applied on top of the generated
+ [`m.room.power_levels`](https://spec.matrix.org/v1.18/client-server-api/#mroompower_levels)
+ event content prior to it being sent to the room. Defaults to overriding
+ nothing.
+ """
+
+ preset: Literal["private_chat", "public_chat", "trusted_private_chat"]
+ """
+ Convenience parameter for setting various default state events based on a
+ preset.
+
+ If unspecified, the server should use the `visibility` to determine which preset
+ to use. A visibility of `public` equates to a preset of `public_chat` and
+ `private` visibility equates to a preset of `private_chat`.
+ """
+
+ room_alias_name: str
+ """The desired room alias **local part**.
+
+ If this is included, a room alias will be created and mapped to the newly
+ created room. The alias will belong on the _same_ homeserver which created the
+ room. For example, if this was set to "foo" and sent to the homeserver
+ "example.com" the complete room alias would be `#foo:example.com`.
+
+ The complete room alias will become the canonical alias for the room and an
+ `m.room.canonical_alias` event will be sent into the room.
+ """
+
+ room_version: str
+ """The room version to set for the room.
+
+ If not provided, the homeserver is to use its configured default. If provided,
+ the homeserver will return a 400 error with the errcode
+ `M_UNSUPPORTED_ROOM_VERSION` if it does not support the room version.
+ """
+
+ topic: str
+ """
+ If this is included, an
+ [`m.room.topic`](https://spec.matrix.org/v1.18/client-server-api/#mroomtopic)
+ event with a `text/plain` mimetype will be sent into the room to indicate the
+ topic for the room. This overwrites any
+ [`m.room.topic`](https://spec.matrix.org/v1.18/client-server-api/#mroomtopic)
+ event in `initial_state`.
+ """
+
+ visibility: Literal["public", "private"]
+ """
+ The room's visibility in the server's
+ [published room directory](https://spec.matrix.org/v1.18/client-server-api#published-room-directory).
+ Defaults to `private`.
+ """
+
+
+class InitialState(TypedDict, total=False):
+ content: Required[object]
+ """The content of the event."""
+
+ type: Required[str]
+ """The type of event to send."""
+
+ state_key: str
+ """The state_key of the state event. Defaults to an empty string."""
+
+
+class Invite3pid(TypedDict, total=False):
+ address: Required[str]
+ """The invitee's third-party identifier."""
+
+ id_access_token: Required[str]
+ """An access token previously registered with the identity server.
+
+ Servers can treat this as optional to distinguish between r0.5-compatible
+ clients and this specification version.
+ """
+
+ id_server: Required[str]
+ """
+ The hostname+port of the identity server which should be used for third-party
+ identifier lookups.
+ """
+
+ medium: Required[str]
+ """
+ The kind of address being passed in the address field, for example `email` (see
+ [the list of recognised values](https://spec.matrix.org/v1.18/appendices/#3pid-types)).
+ """
diff --git a/src/beeper_desktop_api/types/matrix/room_create_response.py b/src/beeper_desktop_api/types/matrix/room_create_response.py
new file mode 100644
index 0000000..e8559bf
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/room_create_response.py
@@ -0,0 +1,12 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from ..._models import BaseModel
+
+__all__ = ["RoomCreateResponse"]
+
+
+class RoomCreateResponse(BaseModel):
+ """Information about the newly created room."""
+
+ room_id: str
+ """The created room's ID."""
diff --git a/src/beeper_desktop_api/types/matrix/room_join_params.py b/src/beeper_desktop_api/types/matrix/room_join_params.py
new file mode 100644
index 0000000..2bbc93b
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/room_join_params.py
@@ -0,0 +1,49 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Dict
+from typing_extensions import Required, TypedDict
+
+from ..._types import SequenceNotStr
+
+__all__ = ["RoomJoinParams", "ThirdPartySigned"]
+
+
+class RoomJoinParams(TypedDict, total=False):
+ via: SequenceNotStr[str]
+ """The servers to attempt to join the room through.
+
+ One of the servers must be participating in the room.
+ """
+
+ reason: str
+ """
+ Optional reason to be included as the `reason` on the subsequent membership
+ event.
+ """
+
+ third_party_signed: ThirdPartySigned
+ """
+ A signature of an `m.third_party_invite` token to prove that this user owns a
+ third-party identity which has been invited to the room.
+ """
+
+
+class ThirdPartySigned(TypedDict, total=False):
+ """
+ A signature of an `m.third_party_invite` token to prove that this user
+ owns a third-party identity which has been invited to the room.
+ """
+
+ token: Required[str]
+ """The state key of the m.third_party_invite event."""
+
+ mxid: Required[str]
+ """The Matrix ID of the invitee."""
+
+ sender: Required[str]
+ """The Matrix ID of the user who issued the invite."""
+
+ signatures: Required[Dict[str, Dict[str, str]]]
+ """A signatures object containing a signature of the entire signed object."""
diff --git a/src/beeper_desktop_api/types/matrix/room_join_response.py b/src/beeper_desktop_api/types/matrix/room_join_response.py
new file mode 100644
index 0000000..337f661
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/room_join_response.py
@@ -0,0 +1,10 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from ..._models import BaseModel
+
+__all__ = ["RoomJoinResponse"]
+
+
+class RoomJoinResponse(BaseModel):
+ room_id: str
+ """The joined room ID."""
diff --git a/src/beeper_desktop_api/types/matrix/room_leave_params.py b/src/beeper_desktop_api/types/matrix/room_leave_params.py
new file mode 100644
index 0000000..1641101
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/room_leave_params.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__ = ["RoomLeaveParams"]
+
+
+class RoomLeaveParams(TypedDict, total=False):
+ reason: str
+ """
+ Optional reason to be included as the `reason` on the subsequent membership
+ event.
+ """
diff --git a/src/beeper_desktop_api/types/matrix/rooms/__init__.py b/src/beeper_desktop_api/types/matrix/rooms/__init__.py
new file mode 100644
index 0000000..39de1f8
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/rooms/__init__.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .state_list_response import StateListResponse as StateListResponse
+from .state_retrieve_params import StateRetrieveParams as StateRetrieveParams
+from .event_retrieve_response import EventRetrieveResponse as EventRetrieveResponse
+from .state_retrieve_response import StateRetrieveResponse as StateRetrieveResponse
+from .account_data_update_params import AccountDataUpdateParams as AccountDataUpdateParams
diff --git a/src/beeper_desktop_api/types/matrix/rooms/account_data_update_params.py b/src/beeper_desktop_api/types/matrix/rooms/account_data_update_params.py
new file mode 100644
index 0000000..aa8463a
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/rooms/account_data_update_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["AccountDataUpdateParams"]
+
+
+class AccountDataUpdateParams(TypedDict, total=False):
+ user_id: Required[Annotated[str, PropertyInfo(alias="userId")]]
+
+ room_id: Required[Annotated[str, PropertyInfo(alias="roomId")]]
+
+ body: Required[object]
diff --git a/src/beeper_desktop_api/types/matrix/rooms/event_retrieve_response.py b/src/beeper_desktop_api/types/matrix/rooms/event_retrieve_response.py
new file mode 100644
index 0000000..f39b2fe
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/rooms/event_retrieve_response.py
@@ -0,0 +1,94 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from ...._models import BaseModel
+
+__all__ = ["EventRetrieveResponse", "Unsigned"]
+
+
+class Unsigned(BaseModel):
+ age: Optional[int] = None
+ """The time in milliseconds that has elapsed since the event was sent.
+
+ This field is generated by the local homeserver, and may be incorrect if the
+ local time on at least one of the two servers is out of sync, which can cause
+ the age to either be negative or greater than it actually is.
+ """
+
+ membership: Optional[str] = None
+ """The room membership of the user making the request, at the time of the event.
+
+ This property is the value of the `membership` property of the requesting user's
+ [`m.room.member`](https://spec.matrix.org/v1.18/client-server-api#mroommember)
+ state at the point of the event, including any changes caused by the event. If
+ the user had yet to join the room at the time of the event (i.e, they have no
+ `m.room.member` state), this property is set to `leave`.
+
+ Homeservers SHOULD populate this property wherever practical, but they MAY omit
+ it if necessary (for example, if calculating the value is expensive, servers
+ might choose to only implement it in encrypted rooms). The property is _not_
+ normally populated in events pushed to application services via the application
+ service transaction API (where there is no clear definition of "requesting
+ user").
+ """
+
+ prev_content: Optional[object] = None
+ """The previous `content` for this event.
+
+ This field is generated by the local homeserver, and is only returned if the
+ event is a state event, and the client has permission to see the previous
+ content.
+ """
+
+ redacted_because: Optional[object] = None
+
+ transaction_id: Optional[str] = None
+ """
+ The client-supplied
+ [transaction ID](https://spec.matrix.org/v1.18/client-server-api/#transaction-identifiers),
+ for example, provided via
+ `PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`, if the client
+ being given the event is the same one which sent it.
+ """
+
+
+class EventRetrieveResponse(BaseModel):
+ """
+ The format used for events when they are returned from a homeserver to a client
+ via the Client-Server API, or sent to an Application Service via the Application Services API.
+ """
+
+ content: object
+ """The body of this event, as created by the client which sent it."""
+
+ event_id: str
+ """The globally unique identifier for this event."""
+
+ origin_server_ts: int
+ """
+ Timestamp (in milliseconds since the unix epoch) on originating homeserver when
+ this event was sent.
+ """
+
+ room_id: str
+ """The ID of the room associated with this event."""
+
+ sender: str
+ """Contains the fully-qualified ID of the user who sent this event."""
+
+ type: str
+ """The type of the event."""
+
+ state_key: Optional[str] = None
+ """Present if, and only if, this event is a _state_ event.
+
+ The key making this piece of state unique in the room. Note that it is often an
+ empty string.
+
+ State keys starting with an `@` are reserved for referencing user IDs, such as
+ room members. With the exception of a few events, state events set with a given
+ user's ID as the state key MUST only be set by that user.
+ """
+
+ unsigned: Optional[Unsigned] = None
diff --git a/src/beeper_desktop_api/types/matrix/rooms/state_list_response.py b/src/beeper_desktop_api/types/matrix/rooms/state_list_response.py
new file mode 100644
index 0000000..1f879ef
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/rooms/state_list_response.py
@@ -0,0 +1,98 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import TypeAlias
+
+from ...._models import BaseModel
+
+__all__ = ["StateListResponse", "StateListResponseItem", "StateListResponseItemUnsigned"]
+
+
+class StateListResponseItemUnsigned(BaseModel):
+ age: Optional[int] = None
+ """The time in milliseconds that has elapsed since the event was sent.
+
+ This field is generated by the local homeserver, and may be incorrect if the
+ local time on at least one of the two servers is out of sync, which can cause
+ the age to either be negative or greater than it actually is.
+ """
+
+ membership: Optional[str] = None
+ """The room membership of the user making the request, at the time of the event.
+
+ This property is the value of the `membership` property of the requesting user's
+ [`m.room.member`](https://spec.matrix.org/v1.18/client-server-api#mroommember)
+ state at the point of the event, including any changes caused by the event. If
+ the user had yet to join the room at the time of the event (i.e, they have no
+ `m.room.member` state), this property is set to `leave`.
+
+ Homeservers SHOULD populate this property wherever practical, but they MAY omit
+ it if necessary (for example, if calculating the value is expensive, servers
+ might choose to only implement it in encrypted rooms). The property is _not_
+ normally populated in events pushed to application services via the application
+ service transaction API (where there is no clear definition of "requesting
+ user").
+ """
+
+ prev_content: Optional[object] = None
+ """The previous `content` for this event.
+
+ This field is generated by the local homeserver, and is only returned if the
+ event is a state event, and the client has permission to see the previous
+ content.
+ """
+
+ redacted_because: Optional[object] = None
+
+ transaction_id: Optional[str] = None
+ """
+ The client-supplied
+ [transaction ID](https://spec.matrix.org/v1.18/client-server-api/#transaction-identifiers),
+ for example, provided via
+ `PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}`, if the client
+ being given the event is the same one which sent it.
+ """
+
+
+class StateListResponseItem(BaseModel):
+ """
+ The format used for events when they are returned from a homeserver to a client
+ via the Client-Server API, or sent to an Application Service via the Application Services API.
+ """
+
+ content: object
+ """The body of this event, as created by the client which sent it."""
+
+ event_id: str
+ """The globally unique identifier for this event."""
+
+ origin_server_ts: int
+ """
+ Timestamp (in milliseconds since the unix epoch) on originating homeserver when
+ this event was sent.
+ """
+
+ room_id: str
+ """The ID of the room associated with this event."""
+
+ sender: str
+ """Contains the fully-qualified ID of the user who sent this event."""
+
+ type: str
+ """The type of the event."""
+
+ state_key: Optional[str] = None
+ """Present if, and only if, this event is a _state_ event.
+
+ The key making this piece of state unique in the room. Note that it is often an
+ empty string.
+
+ State keys starting with an `@` are reserved for referencing user IDs, such as
+ room members. With the exception of a few events, state events set with a given
+ user's ID as the state key MUST only be set by that user.
+ """
+
+ unsigned: Optional[StateListResponseItemUnsigned] = None
+
+
+StateListResponse: TypeAlias = List[StateListResponseItem]
diff --git a/src/beeper_desktop_api/types/matrix/rooms/state_retrieve_params.py b/src/beeper_desktop_api/types/matrix/rooms/state_retrieve_params.py
new file mode 100644
index 0000000..c2a4d7d
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/rooms/state_retrieve_params.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["StateRetrieveParams"]
+
+
+class StateRetrieveParams(TypedDict, total=False):
+ room_id: Required[Annotated[str, PropertyInfo(alias="roomId")]]
+
+ event_type: Required[Annotated[str, PropertyInfo(alias="eventType")]]
+
+ format: Literal["content", "event"]
+ """The format to use for the returned data.
+
+ `content` (the default) will return only the content of the state event. `event`
+ will return the entire event in the usual format suitable for clients, including
+ fields like event ID, sender and timestamp.
+ """
diff --git a/src/beeper_desktop_api/types/matrix/rooms/state_retrieve_response.py b/src/beeper_desktop_api/types/matrix/rooms/state_retrieve_response.py
new file mode 100644
index 0000000..4f07375
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/rooms/state_retrieve_response.py
@@ -0,0 +1,8 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Dict
+from typing_extensions import TypeAlias
+
+__all__ = ["StateRetrieveResponse"]
+
+StateRetrieveResponse: TypeAlias = Dict[str, object]
diff --git a/src/beeper_desktop_api/types/matrix/user_retrieve_profile_response.py b/src/beeper_desktop_api/types/matrix/user_retrieve_profile_response.py
new file mode 100644
index 0000000..9ad6009
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/user_retrieve_profile_response.py
@@ -0,0 +1,32 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import TYPE_CHECKING, Dict, Optional
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["UserRetrieveProfileResponse"]
+
+
+class UserRetrieveProfileResponse(BaseModel):
+ avatar_url: Optional[str] = None
+ """The user's avatar URL if they have set one, otherwise not present."""
+
+ displayname: Optional[str] = None
+ """The user's display name if they have set one, otherwise not present."""
+
+ m_tz: Optional[str] = FieldInfo(alias="m.tz", default=None)
+ """The user's time zone."""
+
+ 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, object] = 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) -> object: ...
+ else:
+ __pydantic_extra__: Dict[str, object]
diff --git a/src/beeper_desktop_api/types/matrix/users/__init__.py b/src/beeper_desktop_api/types/matrix/users/__init__.py
new file mode 100644
index 0000000..65bf6e2
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/users/__init__.py
@@ -0,0 +1,5 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .account_data_update_params import AccountDataUpdateParams as AccountDataUpdateParams
diff --git a/src/beeper_desktop_api/types/matrix/users/account_data_update_params.py b/src/beeper_desktop_api/types/matrix/users/account_data_update_params.py
new file mode 100644
index 0000000..b1d58de
--- /dev/null
+++ b/src/beeper_desktop_api/types/matrix/users/account_data_update_params.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 Required, Annotated, TypedDict
+
+from ...._utils import PropertyInfo
+
+__all__ = ["AccountDataUpdateParams"]
+
+
+class AccountDataUpdateParams(TypedDict, total=False):
+ user_id: Required[Annotated[str, PropertyInfo(alias="userId")]]
+
+ body: Required[object]
diff --git a/src/beeper_desktop_api/types/shared/__init__.py b/src/beeper_desktop_api/types/shared/__init__.py
index cb669ed..63cd244 100644
--- a/src/beeper_desktop_api/types/shared/__init__.py
+++ b/src/beeper_desktop_api/types/shared/__init__.py
@@ -5,3 +5,4 @@
from .message import Message as Message
from .reaction import Reaction as Reaction
from .attachment import Attachment as Attachment
+from .app_state_snapshot import AppStateSnapshot as AppStateSnapshot
diff --git a/src/beeper_desktop_api/types/shared/app_state_snapshot.py b/src/beeper_desktop_api/types/shared/app_state_snapshot.py
new file mode 100644
index 0000000..88fc131
--- /dev/null
+++ b/src/beeper_desktop_api/types/shared/app_state_snapshot.py
@@ -0,0 +1,154 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["AppStateSnapshot", "E2ee", "E2eeSecrets", "Matrix", "Verification", "VerificationError", "VerificationSas"]
+
+
+class E2eeSecrets(BaseModel):
+ """Encrypted messaging keys available on this device."""
+
+ master_key: bool = FieldInfo(alias="masterKey")
+ """Whether the account identity key is available."""
+
+ megolm_backup_key: bool = FieldInfo(alias="megolmBackupKey")
+ """Whether the encrypted message backup key is available."""
+
+ recovery_code: bool = FieldInfo(alias="recoveryCode")
+ """Whether a recovery key is available."""
+
+ self_signing_key: bool = FieldInfo(alias="selfSigningKey")
+ """Whether the device trust key is available."""
+
+ user_signing_key: bool = FieldInfo(alias="userSigningKey")
+ """Whether the user trust key is available."""
+
+
+class E2ee(BaseModel):
+ """Encrypted messaging setup status."""
+
+ cross_signing: bool = FieldInfo(alias="crossSigning")
+ """Whether this account can verify trusted devices."""
+
+ first_sync_done: bool = FieldInfo(alias="firstSyncDone")
+ """Whether the first encrypted message sync is complete."""
+
+ has_backed_up_code: bool = FieldInfo(alias="hasBackedUpCode")
+ """Whether the user confirmed that they saved their recovery key."""
+
+ initialized: bool
+ """Whether encrypted messaging setup has started."""
+
+ key_backup: bool = FieldInfo(alias="keyBackup")
+ """Whether encrypted message backup is available."""
+
+ secrets: E2eeSecrets
+ """Encrypted messaging keys available on this device."""
+
+ secret_storage: bool = FieldInfo(alias="secretStorage")
+ """Whether secure key storage is available."""
+
+ verified: bool
+ """Whether this device is trusted for encrypted messages."""
+
+ recovery_code_generated_at: Optional[float] = FieldInfo(alias="recoveryCodeGeneratedAt", default=None)
+ """Unix timestamp for when the recovery key was created."""
+
+
+class Matrix(BaseModel):
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ device_id: str = FieldInfo(alias="deviceID")
+ """Current device ID."""
+
+ homeserver: str
+ """Beeper server URL for this account."""
+
+ user_id: str = FieldInfo(alias="userID")
+ """Signed-in Beeper user ID."""
+
+
+class VerificationError(BaseModel):
+ """Verification error details, if verification stopped."""
+
+ code: str
+ """Verification error code."""
+
+ reason: str
+ """User-facing verification error message."""
+
+
+class VerificationSas(BaseModel):
+ """Emoji or number comparison data for verification."""
+
+ decimals: str
+ """Number sequence to compare on both devices."""
+
+ emojis: str
+ """Emoji sequence to compare on both devices."""
+
+
+class Verification(BaseModel):
+ """Trusted-device verification progress."""
+
+ available_actions: List[
+ Literal["create", "qr.scan", "accept", "cancel", "qr.confirmScanned", "sas.start", "sas.confirm"]
+ ] = FieldInfo(alias="availableActions")
+ """Verification actions that are valid for the current state."""
+
+ state: Literal["idle", "requested", "ready", "sas_ready", "qr_scanned", "done", "cancelled", "error"]
+ """Current trusted-device verification state."""
+
+ error: Optional[VerificationError] = None
+ """Verification error details, if verification stopped."""
+
+ from_: Optional[str] = FieldInfo(alias="from", default=None)
+ """User ID that started verification."""
+
+ from_device: Optional[str] = FieldInfo(alias="fromDevice", default=None)
+ """Device that started verification."""
+
+ other_device: Optional[str] = FieldInfo(alias="otherDevice", default=None)
+ """Other device participating in verification."""
+
+ qr_data: Optional[str] = FieldInfo(alias="qrData", default=None)
+ """QR code payload to display for verification."""
+
+ sas: Optional[VerificationSas] = None
+ """Emoji or number comparison data for verification."""
+
+ supports_sas: Optional[bool] = FieldInfo(alias="supportsSAS", default=None)
+ """Whether emoji comparison is available."""
+
+ supports_scan_qr_code: Optional[bool] = FieldInfo(alias="supportsScanQRCode", default=None)
+ """Whether QR code verification is available."""
+
+ verification_id: Optional[str] = FieldInfo(alias="verificationID", default=None)
+ """Verification ID to pass in verification action paths."""
+
+
+class AppStateSnapshot(BaseModel):
+ e2ee: E2ee
+ """Encrypted messaging setup status."""
+
+ state: Literal[
+ "needs-login",
+ "initializing",
+ "needs-cross-signing-setup",
+ "needs-verification",
+ "needs-secrets",
+ "needs-first-sync",
+ "ready",
+ ]
+ """Current onboarding state for Beeper Desktop."""
+
+ matrix: Optional[Matrix] = None
+ """Signed-in account details. Omitted until sign-in is complete."""
+
+ verification: Optional[Verification] = None
+ """Trusted-device verification progress."""
diff --git a/tests/api_resources/app/__init__.py b/tests/api_resources/app/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /dev/null
+++ b/tests/api_resources/app/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/app/e2ee/__init__.py b/tests/api_resources/app/e2ee/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /dev/null
+++ b/tests/api_resources/app/e2ee/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/app/e2ee/recovery_code/__init__.py b/tests/api_resources/app/e2ee/recovery_code/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /dev/null
+++ b/tests/api_resources/app/e2ee/recovery_code/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/app/e2ee/recovery_code/test_reset.py b/tests/api_resources/app/e2ee/recovery_code/test_reset.py
new file mode 100644
index 0000000..34aae1f
--- /dev/null
+++ b/tests/api_resources/app/e2ee/recovery_code/test_reset.py
@@ -0,0 +1,153 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.app.e2ee.recovery_code import (
+ ResetCreateResponse,
+ ResetConfirmResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestReset:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: BeeperDesktop) -> None:
+ reset = client.app.e2ee.recovery_code.reset.create()
+ assert_matches_type(ResetCreateResponse, reset, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: BeeperDesktop) -> None:
+ reset = client.app.e2ee.recovery_code.reset.create(
+ recovery_code="recoveryCode",
+ )
+ assert_matches_type(ResetCreateResponse, reset, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.recovery_code.reset.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ reset = response.parse()
+ assert_matches_type(ResetCreateResponse, reset, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.recovery_code.reset.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ reset = response.parse()
+ assert_matches_type(ResetCreateResponse, reset, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_confirm(self, client: BeeperDesktop) -> None:
+ reset = client.app.e2ee.recovery_code.reset.confirm(
+ recovery_code="x",
+ )
+ assert_matches_type(ResetConfirmResponse, reset, path=["response"])
+
+ @parametrize
+ def test_raw_response_confirm(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.recovery_code.reset.with_raw_response.confirm(
+ recovery_code="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ reset = response.parse()
+ assert_matches_type(ResetConfirmResponse, reset, path=["response"])
+
+ @parametrize
+ def test_streaming_response_confirm(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.recovery_code.reset.with_streaming_response.confirm(
+ recovery_code="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ reset = response.parse()
+ assert_matches_type(ResetConfirmResponse, reset, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncReset:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncBeeperDesktop) -> None:
+ reset = await async_client.app.e2ee.recovery_code.reset.create()
+ assert_matches_type(ResetCreateResponse, reset, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ reset = await async_client.app.e2ee.recovery_code.reset.create(
+ recovery_code="recoveryCode",
+ )
+ assert_matches_type(ResetCreateResponse, reset, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.recovery_code.reset.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ reset = await response.parse()
+ assert_matches_type(ResetCreateResponse, reset, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.recovery_code.reset.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ reset = await response.parse()
+ assert_matches_type(ResetCreateResponse, reset, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_confirm(self, async_client: AsyncBeeperDesktop) -> None:
+ reset = await async_client.app.e2ee.recovery_code.reset.confirm(
+ recovery_code="x",
+ )
+ assert_matches_type(ResetConfirmResponse, reset, path=["response"])
+
+ @parametrize
+ async def test_raw_response_confirm(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.recovery_code.reset.with_raw_response.confirm(
+ recovery_code="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ reset = await response.parse()
+ assert_matches_type(ResetConfirmResponse, reset, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_confirm(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.recovery_code.reset.with_streaming_response.confirm(
+ recovery_code="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ reset = await response.parse()
+ assert_matches_type(ResetConfirmResponse, reset, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/app/e2ee/test_recovery_code.py b/tests/api_resources/app/e2ee/test_recovery_code.py
new file mode 100644
index 0000000..c7caaf9
--- /dev/null
+++ b/tests/api_resources/app/e2ee/test_recovery_code.py
@@ -0,0 +1,139 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.app.e2ee import (
+ RecoveryCodeVerifyResponse,
+ RecoveryCodeMarkBackedUpResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestRecoveryCode:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_mark_backed_up(self, client: BeeperDesktop) -> None:
+ recovery_code = client.app.e2ee.recovery_code.mark_backed_up()
+ assert_matches_type(RecoveryCodeMarkBackedUpResponse, recovery_code, path=["response"])
+
+ @parametrize
+ def test_raw_response_mark_backed_up(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.recovery_code.with_raw_response.mark_backed_up()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ recovery_code = response.parse()
+ assert_matches_type(RecoveryCodeMarkBackedUpResponse, recovery_code, path=["response"])
+
+ @parametrize
+ def test_streaming_response_mark_backed_up(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.recovery_code.with_streaming_response.mark_backed_up() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ recovery_code = response.parse()
+ assert_matches_type(RecoveryCodeMarkBackedUpResponse, recovery_code, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_verify(self, client: BeeperDesktop) -> None:
+ recovery_code = client.app.e2ee.recovery_code.verify(
+ recovery_code="x",
+ )
+ assert_matches_type(RecoveryCodeVerifyResponse, recovery_code, path=["response"])
+
+ @parametrize
+ def test_raw_response_verify(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.recovery_code.with_raw_response.verify(
+ recovery_code="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ recovery_code = response.parse()
+ assert_matches_type(RecoveryCodeVerifyResponse, recovery_code, path=["response"])
+
+ @parametrize
+ def test_streaming_response_verify(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.recovery_code.with_streaming_response.verify(
+ recovery_code="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ recovery_code = response.parse()
+ assert_matches_type(RecoveryCodeVerifyResponse, recovery_code, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncRecoveryCode:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_mark_backed_up(self, async_client: AsyncBeeperDesktop) -> None:
+ recovery_code = await async_client.app.e2ee.recovery_code.mark_backed_up()
+ assert_matches_type(RecoveryCodeMarkBackedUpResponse, recovery_code, path=["response"])
+
+ @parametrize
+ async def test_raw_response_mark_backed_up(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.recovery_code.with_raw_response.mark_backed_up()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ recovery_code = await response.parse()
+ assert_matches_type(RecoveryCodeMarkBackedUpResponse, recovery_code, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_mark_backed_up(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.recovery_code.with_streaming_response.mark_backed_up() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ recovery_code = await response.parse()
+ assert_matches_type(RecoveryCodeMarkBackedUpResponse, recovery_code, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_verify(self, async_client: AsyncBeeperDesktop) -> None:
+ recovery_code = await async_client.app.e2ee.recovery_code.verify(
+ recovery_code="x",
+ )
+ assert_matches_type(RecoveryCodeVerifyResponse, recovery_code, path=["response"])
+
+ @parametrize
+ async def test_raw_response_verify(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.recovery_code.with_raw_response.verify(
+ recovery_code="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ recovery_code = await response.parse()
+ assert_matches_type(RecoveryCodeVerifyResponse, recovery_code, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_verify(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.recovery_code.with_streaming_response.verify(
+ recovery_code="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ recovery_code = await response.parse()
+ assert_matches_type(RecoveryCodeVerifyResponse, recovery_code, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/app/e2ee/test_verification.py b/tests/api_resources/app/e2ee/test_verification.py
new file mode 100644
index 0000000..1700f2d
--- /dev/null
+++ b/tests/api_resources/app/e2ee/test_verification.py
@@ -0,0 +1,262 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.app.e2ee import (
+ VerificationAcceptResponse,
+ VerificationCancelResponse,
+ VerificationCreateResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestVerification:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: BeeperDesktop) -> None:
+ verification = client.app.e2ee.verification.create()
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: BeeperDesktop) -> None:
+ verification = client.app.e2ee.verification.create(
+ user_id="userID",
+ )
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.verification.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = response.parse()
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.verification.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = response.parse()
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_accept(self, client: BeeperDesktop) -> None:
+ verification = client.app.e2ee.verification.accept(
+ "x",
+ )
+ assert_matches_type(VerificationAcceptResponse, verification, path=["response"])
+
+ @parametrize
+ def test_raw_response_accept(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.verification.with_raw_response.accept(
+ "x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = response.parse()
+ assert_matches_type(VerificationAcceptResponse, verification, path=["response"])
+
+ @parametrize
+ def test_streaming_response_accept(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.verification.with_streaming_response.accept(
+ "x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = response.parse()
+ assert_matches_type(VerificationAcceptResponse, verification, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_accept(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ client.app.e2ee.verification.with_raw_response.accept(
+ "",
+ )
+
+ @parametrize
+ def test_method_cancel(self, client: BeeperDesktop) -> None:
+ verification = client.app.e2ee.verification.cancel(
+ verification_id="x",
+ )
+ assert_matches_type(VerificationCancelResponse, verification, path=["response"])
+
+ @parametrize
+ def test_method_cancel_with_all_params(self, client: BeeperDesktop) -> None:
+ verification = client.app.e2ee.verification.cancel(
+ verification_id="x",
+ code="code",
+ reason="reason",
+ )
+ assert_matches_type(VerificationCancelResponse, verification, path=["response"])
+
+ @parametrize
+ def test_raw_response_cancel(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.verification.with_raw_response.cancel(
+ verification_id="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = response.parse()
+ assert_matches_type(VerificationCancelResponse, verification, path=["response"])
+
+ @parametrize
+ def test_streaming_response_cancel(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.verification.with_streaming_response.cancel(
+ verification_id="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = response.parse()
+ assert_matches_type(VerificationCancelResponse, verification, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_cancel(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ client.app.e2ee.verification.with_raw_response.cancel(
+ verification_id="",
+ )
+
+
+class TestAsyncVerification:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncBeeperDesktop) -> None:
+ verification = await async_client.app.e2ee.verification.create()
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ verification = await async_client.app.e2ee.verification.create(
+ user_id="userID",
+ )
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.verification.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = await response.parse()
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.verification.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = await response.parse()
+ assert_matches_type(VerificationCreateResponse, verification, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_accept(self, async_client: AsyncBeeperDesktop) -> None:
+ verification = await async_client.app.e2ee.verification.accept(
+ "x",
+ )
+ assert_matches_type(VerificationAcceptResponse, verification, path=["response"])
+
+ @parametrize
+ async def test_raw_response_accept(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.verification.with_raw_response.accept(
+ "x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = await response.parse()
+ assert_matches_type(VerificationAcceptResponse, verification, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_accept(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.verification.with_streaming_response.accept(
+ "x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = await response.parse()
+ assert_matches_type(VerificationAcceptResponse, verification, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_accept(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ await async_client.app.e2ee.verification.with_raw_response.accept(
+ "",
+ )
+
+ @parametrize
+ async def test_method_cancel(self, async_client: AsyncBeeperDesktop) -> None:
+ verification = await async_client.app.e2ee.verification.cancel(
+ verification_id="x",
+ )
+ assert_matches_type(VerificationCancelResponse, verification, path=["response"])
+
+ @parametrize
+ async def test_method_cancel_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ verification = await async_client.app.e2ee.verification.cancel(
+ verification_id="x",
+ code="code",
+ reason="reason",
+ )
+ assert_matches_type(VerificationCancelResponse, verification, path=["response"])
+
+ @parametrize
+ async def test_raw_response_cancel(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.verification.with_raw_response.cancel(
+ verification_id="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ verification = await response.parse()
+ assert_matches_type(VerificationCancelResponse, verification, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_cancel(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.verification.with_streaming_response.cancel(
+ verification_id="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ verification = await response.parse()
+ assert_matches_type(VerificationCancelResponse, verification, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_cancel(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ await async_client.app.e2ee.verification.with_raw_response.cancel(
+ verification_id="",
+ )
diff --git a/tests/api_resources/app/e2ee/verification/__init__.py b/tests/api_resources/app/e2ee/verification/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /dev/null
+++ b/tests/api_resources/app/e2ee/verification/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/app/e2ee/verification/test_qr.py b/tests/api_resources/app/e2ee/verification/test_qr.py
new file mode 100644
index 0000000..9eb8e0c
--- /dev/null
+++ b/tests/api_resources/app/e2ee/verification/test_qr.py
@@ -0,0 +1,162 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.app.e2ee.verification import QrScanResponse, QrConfirmScannedResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestQr:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_confirm_scanned(self, client: BeeperDesktop) -> None:
+ qr = client.app.e2ee.verification.qr.confirm_scanned(
+ "x",
+ )
+ assert_matches_type(QrConfirmScannedResponse, qr, path=["response"])
+
+ @parametrize
+ def test_raw_response_confirm_scanned(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.verification.qr.with_raw_response.confirm_scanned(
+ "x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ qr = response.parse()
+ assert_matches_type(QrConfirmScannedResponse, qr, path=["response"])
+
+ @parametrize
+ def test_streaming_response_confirm_scanned(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.verification.qr.with_streaming_response.confirm_scanned(
+ "x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ qr = response.parse()
+ assert_matches_type(QrConfirmScannedResponse, qr, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_confirm_scanned(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ client.app.e2ee.verification.qr.with_raw_response.confirm_scanned(
+ "",
+ )
+
+ @parametrize
+ def test_method_scan(self, client: BeeperDesktop) -> None:
+ qr = client.app.e2ee.verification.qr.scan(
+ data="x",
+ )
+ assert_matches_type(QrScanResponse, qr, path=["response"])
+
+ @parametrize
+ def test_raw_response_scan(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.verification.qr.with_raw_response.scan(
+ data="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ qr = response.parse()
+ assert_matches_type(QrScanResponse, qr, path=["response"])
+
+ @parametrize
+ def test_streaming_response_scan(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.verification.qr.with_streaming_response.scan(
+ data="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ qr = response.parse()
+ assert_matches_type(QrScanResponse, qr, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncQr:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_confirm_scanned(self, async_client: AsyncBeeperDesktop) -> None:
+ qr = await async_client.app.e2ee.verification.qr.confirm_scanned(
+ "x",
+ )
+ assert_matches_type(QrConfirmScannedResponse, qr, path=["response"])
+
+ @parametrize
+ async def test_raw_response_confirm_scanned(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.verification.qr.with_raw_response.confirm_scanned(
+ "x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ qr = await response.parse()
+ assert_matches_type(QrConfirmScannedResponse, qr, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_confirm_scanned(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.verification.qr.with_streaming_response.confirm_scanned(
+ "x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ qr = await response.parse()
+ assert_matches_type(QrConfirmScannedResponse, qr, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_confirm_scanned(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ await async_client.app.e2ee.verification.qr.with_raw_response.confirm_scanned(
+ "",
+ )
+
+ @parametrize
+ async def test_method_scan(self, async_client: AsyncBeeperDesktop) -> None:
+ qr = await async_client.app.e2ee.verification.qr.scan(
+ data="x",
+ )
+ assert_matches_type(QrScanResponse, qr, path=["response"])
+
+ @parametrize
+ async def test_raw_response_scan(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.verification.qr.with_raw_response.scan(
+ data="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ qr = await response.parse()
+ assert_matches_type(QrScanResponse, qr, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_scan(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.verification.qr.with_streaming_response.scan(
+ data="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ qr = await response.parse()
+ assert_matches_type(QrScanResponse, qr, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/app/e2ee/verification/test_sas.py b/tests/api_resources/app/e2ee/verification/test_sas.py
new file mode 100644
index 0000000..7a8c43c
--- /dev/null
+++ b/tests/api_resources/app/e2ee/verification/test_sas.py
@@ -0,0 +1,176 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.app.e2ee.verification import SaStartResponse, SaConfirmResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestSas:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_confirm(self, client: BeeperDesktop) -> None:
+ sa = client.app.e2ee.verification.sas.confirm(
+ "x",
+ )
+ assert_matches_type(SaConfirmResponse, sa, path=["response"])
+
+ @parametrize
+ def test_raw_response_confirm(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.verification.sas.with_raw_response.confirm(
+ "x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ sa = response.parse()
+ assert_matches_type(SaConfirmResponse, sa, path=["response"])
+
+ @parametrize
+ def test_streaming_response_confirm(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.verification.sas.with_streaming_response.confirm(
+ "x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ sa = response.parse()
+ assert_matches_type(SaConfirmResponse, sa, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_confirm(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ client.app.e2ee.verification.sas.with_raw_response.confirm(
+ "",
+ )
+
+ @parametrize
+ def test_method_start(self, client: BeeperDesktop) -> None:
+ sa = client.app.e2ee.verification.sas.start(
+ "x",
+ )
+ assert_matches_type(SaStartResponse, sa, path=["response"])
+
+ @parametrize
+ def test_raw_response_start(self, client: BeeperDesktop) -> None:
+ response = client.app.e2ee.verification.sas.with_raw_response.start(
+ "x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ sa = response.parse()
+ assert_matches_type(SaStartResponse, sa, path=["response"])
+
+ @parametrize
+ def test_streaming_response_start(self, client: BeeperDesktop) -> None:
+ with client.app.e2ee.verification.sas.with_streaming_response.start(
+ "x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ sa = response.parse()
+ assert_matches_type(SaStartResponse, sa, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_start(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ client.app.e2ee.verification.sas.with_raw_response.start(
+ "",
+ )
+
+
+class TestAsyncSas:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_confirm(self, async_client: AsyncBeeperDesktop) -> None:
+ sa = await async_client.app.e2ee.verification.sas.confirm(
+ "x",
+ )
+ assert_matches_type(SaConfirmResponse, sa, path=["response"])
+
+ @parametrize
+ async def test_raw_response_confirm(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.verification.sas.with_raw_response.confirm(
+ "x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ sa = await response.parse()
+ assert_matches_type(SaConfirmResponse, sa, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_confirm(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.verification.sas.with_streaming_response.confirm(
+ "x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ sa = await response.parse()
+ assert_matches_type(SaConfirmResponse, sa, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_confirm(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ await async_client.app.e2ee.verification.sas.with_raw_response.confirm(
+ "",
+ )
+
+ @parametrize
+ async def test_method_start(self, async_client: AsyncBeeperDesktop) -> None:
+ sa = await async_client.app.e2ee.verification.sas.start(
+ "x",
+ )
+ assert_matches_type(SaStartResponse, sa, path=["response"])
+
+ @parametrize
+ async def test_raw_response_start(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.e2ee.verification.sas.with_raw_response.start(
+ "x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ sa = await response.parse()
+ assert_matches_type(SaStartResponse, sa, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_start(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.e2ee.verification.sas.with_streaming_response.start(
+ "x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ sa = await response.parse()
+ assert_matches_type(SaStartResponse, sa, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_start(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `verification_id` but received ''"):
+ await async_client.app.e2ee.verification.sas.with_raw_response.start(
+ "",
+ )
diff --git a/tests/api_resources/app/test_login.py b/tests/api_resources/app/test_login.py
new file mode 100644
index 0000000..7963136
--- /dev/null
+++ b/tests/api_resources/app/test_login.py
@@ -0,0 +1,294 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.app import (
+ LoginStartResponse,
+ LoginRegisterResponse,
+ LoginResponseResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestLogin:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_email(self, client: BeeperDesktop) -> None:
+ login = client.app.login.email(
+ email="dev@stainless.com",
+ request="request",
+ )
+ assert_matches_type(object, login, path=["response"])
+
+ @parametrize
+ def test_raw_response_email(self, client: BeeperDesktop) -> None:
+ response = client.app.login.with_raw_response.email(
+ email="dev@stainless.com",
+ request="request",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ login = response.parse()
+ assert_matches_type(object, login, path=["response"])
+
+ @parametrize
+ def test_streaming_response_email(self, client: BeeperDesktop) -> None:
+ with client.app.login.with_streaming_response.email(
+ email="dev@stainless.com",
+ request="request",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ login = response.parse()
+ assert_matches_type(object, login, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_register(self, client: BeeperDesktop) -> None:
+ login = client.app.login.register(
+ accept_terms=True,
+ lead_token="leadToken",
+ request="request",
+ username="x",
+ )
+ assert_matches_type(LoginRegisterResponse, login, path=["response"])
+
+ @parametrize
+ def test_raw_response_register(self, client: BeeperDesktop) -> None:
+ response = client.app.login.with_raw_response.register(
+ accept_terms=True,
+ lead_token="leadToken",
+ request="request",
+ username="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ login = response.parse()
+ assert_matches_type(LoginRegisterResponse, login, path=["response"])
+
+ @parametrize
+ def test_streaming_response_register(self, client: BeeperDesktop) -> None:
+ with client.app.login.with_streaming_response.register(
+ accept_terms=True,
+ lead_token="leadToken",
+ request="request",
+ username="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ login = response.parse()
+ assert_matches_type(LoginRegisterResponse, login, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_response(self, client: BeeperDesktop) -> None:
+ login = client.app.login.response(
+ request="request",
+ response="response",
+ )
+ assert_matches_type(LoginResponseResponse, login, path=["response"])
+
+ @parametrize
+ def test_raw_response_response(self, client: BeeperDesktop) -> None:
+ response = client.app.login.with_raw_response.response(
+ request="request",
+ response="response",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ login = response.parse()
+ assert_matches_type(LoginResponseResponse, login, path=["response"])
+
+ @parametrize
+ def test_streaming_response_response(self, client: BeeperDesktop) -> None:
+ with client.app.login.with_streaming_response.response(
+ request="request",
+ response="response",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ login = response.parse()
+ assert_matches_type(LoginResponseResponse, login, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_start(self, client: BeeperDesktop) -> None:
+ login = client.app.login.start()
+ assert_matches_type(LoginStartResponse, login, path=["response"])
+
+ @parametrize
+ def test_raw_response_start(self, client: BeeperDesktop) -> None:
+ response = client.app.login.with_raw_response.start()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ login = response.parse()
+ assert_matches_type(LoginStartResponse, login, path=["response"])
+
+ @parametrize
+ def test_streaming_response_start(self, client: BeeperDesktop) -> None:
+ with client.app.login.with_streaming_response.start() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ login = response.parse()
+ assert_matches_type(LoginStartResponse, login, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncLogin:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_email(self, async_client: AsyncBeeperDesktop) -> None:
+ login = await async_client.app.login.email(
+ email="dev@stainless.com",
+ request="request",
+ )
+ assert_matches_type(object, login, path=["response"])
+
+ @parametrize
+ async def test_raw_response_email(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.login.with_raw_response.email(
+ email="dev@stainless.com",
+ request="request",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ login = await response.parse()
+ assert_matches_type(object, login, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_email(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.login.with_streaming_response.email(
+ email="dev@stainless.com",
+ request="request",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ login = await response.parse()
+ assert_matches_type(object, login, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_register(self, async_client: AsyncBeeperDesktop) -> None:
+ login = await async_client.app.login.register(
+ accept_terms=True,
+ lead_token="leadToken",
+ request="request",
+ username="x",
+ )
+ assert_matches_type(LoginRegisterResponse, login, path=["response"])
+
+ @parametrize
+ async def test_raw_response_register(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.login.with_raw_response.register(
+ accept_terms=True,
+ lead_token="leadToken",
+ request="request",
+ username="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ login = await response.parse()
+ assert_matches_type(LoginRegisterResponse, login, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_register(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.login.with_streaming_response.register(
+ accept_terms=True,
+ lead_token="leadToken",
+ request="request",
+ username="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ login = await response.parse()
+ assert_matches_type(LoginRegisterResponse, login, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_response(self, async_client: AsyncBeeperDesktop) -> None:
+ login = await async_client.app.login.response(
+ request="request",
+ response="response",
+ )
+ assert_matches_type(LoginResponseResponse, login, path=["response"])
+
+ @parametrize
+ async def test_raw_response_response(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.login.with_raw_response.response(
+ request="request",
+ response="response",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ login = await response.parse()
+ assert_matches_type(LoginResponseResponse, login, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_response(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.login.with_streaming_response.response(
+ request="request",
+ response="response",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ login = await response.parse()
+ assert_matches_type(LoginResponseResponse, login, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_start(self, async_client: AsyncBeeperDesktop) -> None:
+ login = await async_client.app.login.start()
+ assert_matches_type(LoginStartResponse, login, path=["response"])
+
+ @parametrize
+ async def test_raw_response_start(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.login.with_raw_response.start()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ login = await response.parse()
+ assert_matches_type(LoginStartResponse, login, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_start(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.login.with_streaming_response.start() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ login = await response.parse()
+ assert_matches_type(LoginStartResponse, login, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/matrix/__init__.py b/tests/api_resources/matrix/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /dev/null
+++ b/tests/api_resources/matrix/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/matrix/bridges/__init__.py b/tests/api_resources/matrix/bridges/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /dev/null
+++ b/tests/api_resources/matrix/bridges/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/matrix/bridges/test_auth.py b/tests/api_resources/matrix/bridges/test_auth.py
new file mode 100644
index 0000000..bdb57e4
--- /dev/null
+++ b/tests/api_resources/matrix/bridges/test_auth.py
@@ -0,0 +1,854 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.matrix.bridges import (
+ AuthWhoamiResponse,
+ AuthListFlowsResponse,
+ AuthListLoginsResponse,
+ AuthStartLoginResponse,
+ AuthWaitForStepResponse,
+ AuthSubmitCookiesResponse,
+ AuthSubmitUserInputResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestAuth:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_list_flows(self, client: BeeperDesktop) -> None:
+ auth = client.matrix.bridges.auth.list_flows(
+ "bridgeID",
+ )
+ assert_matches_type(AuthListFlowsResponse, auth, path=["response"])
+
+ @parametrize
+ def test_raw_response_list_flows(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.auth.with_raw_response.list_flows(
+ "bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = response.parse()
+ assert_matches_type(AuthListFlowsResponse, auth, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list_flows(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.auth.with_streaming_response.list_flows(
+ "bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = response.parse()
+ assert_matches_type(AuthListFlowsResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list_flows(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.list_flows(
+ "",
+ )
+
+ @parametrize
+ def test_method_list_logins(self, client: BeeperDesktop) -> None:
+ auth = client.matrix.bridges.auth.list_logins(
+ "bridgeID",
+ )
+ assert_matches_type(AuthListLoginsResponse, auth, path=["response"])
+
+ @parametrize
+ def test_raw_response_list_logins(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.auth.with_raw_response.list_logins(
+ "bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = response.parse()
+ assert_matches_type(AuthListLoginsResponse, auth, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list_logins(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.auth.with_streaming_response.list_logins(
+ "bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = response.parse()
+ assert_matches_type(AuthListLoginsResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list_logins(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.list_logins(
+ "",
+ )
+
+ @parametrize
+ def test_method_logout(self, client: BeeperDesktop) -> None:
+ auth = client.matrix.bridges.auth.logout(
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(object, auth, path=["response"])
+
+ @parametrize
+ def test_raw_response_logout(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.auth.with_raw_response.logout(
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = response.parse()
+ assert_matches_type(object, auth, path=["response"])
+
+ @parametrize
+ def test_streaming_response_logout(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.auth.with_streaming_response.logout(
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = response.parse()
+ assert_matches_type(object, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_logout(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.logout(
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `login_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.logout(
+ login_id="",
+ bridge_id="bridgeID",
+ )
+
+ @parametrize
+ def test_method_start_login(self, client: BeeperDesktop) -> None:
+ auth = client.matrix.bridges.auth.start_login(
+ flow_id="qr",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(AuthStartLoginResponse, auth, path=["response"])
+
+ @parametrize
+ def test_method_start_login_with_all_params(self, client: BeeperDesktop) -> None:
+ auth = client.matrix.bridges.auth.start_login(
+ flow_id="qr",
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ )
+ assert_matches_type(AuthStartLoginResponse, auth, path=["response"])
+
+ @parametrize
+ def test_raw_response_start_login(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.auth.with_raw_response.start_login(
+ flow_id="qr",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = response.parse()
+ assert_matches_type(AuthStartLoginResponse, auth, path=["response"])
+
+ @parametrize
+ def test_streaming_response_start_login(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.auth.with_streaming_response.start_login(
+ flow_id="qr",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = response.parse()
+ assert_matches_type(AuthStartLoginResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_start_login(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.start_login(
+ flow_id="qr",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `flow_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.start_login(
+ flow_id="",
+ bridge_id="bridgeID",
+ )
+
+ @parametrize
+ def test_method_submit_cookies(self, client: BeeperDesktop) -> None:
+ auth = client.matrix.bridges.auth.submit_cookies(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+ assert_matches_type(AuthSubmitCookiesResponse, auth, path=["response"])
+
+ @parametrize
+ def test_raw_response_submit_cookies(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.auth.with_raw_response.submit_cookies(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = response.parse()
+ assert_matches_type(AuthSubmitCookiesResponse, auth, path=["response"])
+
+ @parametrize
+ def test_streaming_response_submit_cookies(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.auth.with_streaming_response.submit_cookies(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = response.parse()
+ assert_matches_type(AuthSubmitCookiesResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_submit_cookies(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.submit_cookies(
+ step_id="stepID",
+ bridge_id="",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `login_process_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.submit_cookies(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="",
+ body={"foo": "string"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.submit_cookies(
+ step_id="",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ @parametrize
+ def test_method_submit_user_input(self, client: BeeperDesktop) -> None:
+ auth = client.matrix.bridges.auth.submit_user_input(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+ assert_matches_type(AuthSubmitUserInputResponse, auth, path=["response"])
+
+ @parametrize
+ def test_raw_response_submit_user_input(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.auth.with_raw_response.submit_user_input(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = response.parse()
+ assert_matches_type(AuthSubmitUserInputResponse, auth, path=["response"])
+
+ @parametrize
+ def test_streaming_response_submit_user_input(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.auth.with_streaming_response.submit_user_input(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = response.parse()
+ assert_matches_type(AuthSubmitUserInputResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_submit_user_input(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.submit_user_input(
+ step_id="stepID",
+ bridge_id="",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `login_process_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.submit_user_input(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="",
+ body={"foo": "string"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.submit_user_input(
+ step_id="",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ @parametrize
+ def test_method_wait_for_step(self, client: BeeperDesktop) -> None:
+ auth = client.matrix.bridges.auth.wait_for_step(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ )
+ assert_matches_type(AuthWaitForStepResponse, auth, path=["response"])
+
+ @parametrize
+ def test_raw_response_wait_for_step(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.auth.with_raw_response.wait_for_step(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = response.parse()
+ assert_matches_type(AuthWaitForStepResponse, auth, path=["response"])
+
+ @parametrize
+ def test_streaming_response_wait_for_step(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.auth.with_streaming_response.wait_for_step(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = response.parse()
+ assert_matches_type(AuthWaitForStepResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_wait_for_step(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.wait_for_step(
+ step_id="stepID",
+ bridge_id="",
+ login_process_id="loginProcessID",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `login_process_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.wait_for_step(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.wait_for_step(
+ step_id="",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ )
+
+ @parametrize
+ def test_method_whoami(self, client: BeeperDesktop) -> None:
+ auth = client.matrix.bridges.auth.whoami(
+ "bridgeID",
+ )
+ assert_matches_type(AuthWhoamiResponse, auth, path=["response"])
+
+ @parametrize
+ def test_raw_response_whoami(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.auth.with_raw_response.whoami(
+ "bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = response.parse()
+ assert_matches_type(AuthWhoamiResponse, auth, path=["response"])
+
+ @parametrize
+ def test_streaming_response_whoami(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.auth.with_streaming_response.whoami(
+ "bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = response.parse()
+ assert_matches_type(AuthWhoamiResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_whoami(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.auth.with_raw_response.whoami(
+ "",
+ )
+
+
+class TestAsyncAuth:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_list_flows(self, async_client: AsyncBeeperDesktop) -> None:
+ auth = await async_client.matrix.bridges.auth.list_flows(
+ "bridgeID",
+ )
+ assert_matches_type(AuthListFlowsResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list_flows(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.auth.with_raw_response.list_flows(
+ "bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = await response.parse()
+ assert_matches_type(AuthListFlowsResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list_flows(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.auth.with_streaming_response.list_flows(
+ "bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = await response.parse()
+ assert_matches_type(AuthListFlowsResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list_flows(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.list_flows(
+ "",
+ )
+
+ @parametrize
+ async def test_method_list_logins(self, async_client: AsyncBeeperDesktop) -> None:
+ auth = await async_client.matrix.bridges.auth.list_logins(
+ "bridgeID",
+ )
+ assert_matches_type(AuthListLoginsResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list_logins(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.auth.with_raw_response.list_logins(
+ "bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = await response.parse()
+ assert_matches_type(AuthListLoginsResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list_logins(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.auth.with_streaming_response.list_logins(
+ "bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = await response.parse()
+ assert_matches_type(AuthListLoginsResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list_logins(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.list_logins(
+ "",
+ )
+
+ @parametrize
+ async def test_method_logout(self, async_client: AsyncBeeperDesktop) -> None:
+ auth = await async_client.matrix.bridges.auth.logout(
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(object, auth, path=["response"])
+
+ @parametrize
+ async def test_raw_response_logout(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.auth.with_raw_response.logout(
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = await response.parse()
+ assert_matches_type(object, auth, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_logout(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.auth.with_streaming_response.logout(
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = await response.parse()
+ assert_matches_type(object, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_logout(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.logout(
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `login_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.logout(
+ login_id="",
+ bridge_id="bridgeID",
+ )
+
+ @parametrize
+ async def test_method_start_login(self, async_client: AsyncBeeperDesktop) -> None:
+ auth = await async_client.matrix.bridges.auth.start_login(
+ flow_id="qr",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(AuthStartLoginResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_method_start_login_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ auth = await async_client.matrix.bridges.auth.start_login(
+ flow_id="qr",
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ )
+ assert_matches_type(AuthStartLoginResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_raw_response_start_login(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.auth.with_raw_response.start_login(
+ flow_id="qr",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = await response.parse()
+ assert_matches_type(AuthStartLoginResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_start_login(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.auth.with_streaming_response.start_login(
+ flow_id="qr",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = await response.parse()
+ assert_matches_type(AuthStartLoginResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_start_login(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.start_login(
+ flow_id="qr",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `flow_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.start_login(
+ flow_id="",
+ bridge_id="bridgeID",
+ )
+
+ @parametrize
+ async def test_method_submit_cookies(self, async_client: AsyncBeeperDesktop) -> None:
+ auth = await async_client.matrix.bridges.auth.submit_cookies(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+ assert_matches_type(AuthSubmitCookiesResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_raw_response_submit_cookies(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.auth.with_raw_response.submit_cookies(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = await response.parse()
+ assert_matches_type(AuthSubmitCookiesResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_submit_cookies(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.auth.with_streaming_response.submit_cookies(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = await response.parse()
+ assert_matches_type(AuthSubmitCookiesResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_submit_cookies(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.submit_cookies(
+ step_id="stepID",
+ bridge_id="",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `login_process_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.submit_cookies(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="",
+ body={"foo": "string"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.submit_cookies(
+ step_id="",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ @parametrize
+ async def test_method_submit_user_input(self, async_client: AsyncBeeperDesktop) -> None:
+ auth = await async_client.matrix.bridges.auth.submit_user_input(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+ assert_matches_type(AuthSubmitUserInputResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_raw_response_submit_user_input(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.auth.with_raw_response.submit_user_input(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = await response.parse()
+ assert_matches_type(AuthSubmitUserInputResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_submit_user_input(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.auth.with_streaming_response.submit_user_input(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = await response.parse()
+ assert_matches_type(AuthSubmitUserInputResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_submit_user_input(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.submit_user_input(
+ step_id="stepID",
+ bridge_id="",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `login_process_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.submit_user_input(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="",
+ body={"foo": "string"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.submit_user_input(
+ step_id="",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ body={"foo": "string"},
+ )
+
+ @parametrize
+ async def test_method_wait_for_step(self, async_client: AsyncBeeperDesktop) -> None:
+ auth = await async_client.matrix.bridges.auth.wait_for_step(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ )
+ assert_matches_type(AuthWaitForStepResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_raw_response_wait_for_step(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.auth.with_raw_response.wait_for_step(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = await response.parse()
+ assert_matches_type(AuthWaitForStepResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_wait_for_step(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.auth.with_streaming_response.wait_for_step(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = await response.parse()
+ assert_matches_type(AuthWaitForStepResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_wait_for_step(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.wait_for_step(
+ step_id="stepID",
+ bridge_id="",
+ login_process_id="loginProcessID",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `login_process_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.wait_for_step(
+ step_id="stepID",
+ bridge_id="bridgeID",
+ login_process_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `step_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.wait_for_step(
+ step_id="",
+ bridge_id="bridgeID",
+ login_process_id="loginProcessID",
+ )
+
+ @parametrize
+ async def test_method_whoami(self, async_client: AsyncBeeperDesktop) -> None:
+ auth = await async_client.matrix.bridges.auth.whoami(
+ "bridgeID",
+ )
+ assert_matches_type(AuthWhoamiResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_raw_response_whoami(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.auth.with_raw_response.whoami(
+ "bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ auth = await response.parse()
+ assert_matches_type(AuthWhoamiResponse, auth, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_whoami(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.auth.with_streaming_response.whoami(
+ "bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ auth = await response.parse()
+ assert_matches_type(AuthWhoamiResponse, auth, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_whoami(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.auth.with_raw_response.whoami(
+ "",
+ )
diff --git a/tests/api_resources/matrix/bridges/test_capabilities.py b/tests/api_resources/matrix/bridges/test_capabilities.py
new file mode 100644
index 0000000..c1c6fc7
--- /dev/null
+++ b/tests/api_resources/matrix/bridges/test_capabilities.py
@@ -0,0 +1,100 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.matrix.bridges import CapabilityRetrieveResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestCapabilities:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: BeeperDesktop) -> None:
+ capability = client.matrix.bridges.capabilities.retrieve(
+ "bridgeID",
+ )
+ assert_matches_type(CapabilityRetrieveResponse, capability, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.capabilities.with_raw_response.retrieve(
+ "bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ capability = response.parse()
+ assert_matches_type(CapabilityRetrieveResponse, capability, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.capabilities.with_streaming_response.retrieve(
+ "bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ capability = response.parse()
+ assert_matches_type(CapabilityRetrieveResponse, capability, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.capabilities.with_raw_response.retrieve(
+ "",
+ )
+
+
+class TestAsyncCapabilities:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ capability = await async_client.matrix.bridges.capabilities.retrieve(
+ "bridgeID",
+ )
+ assert_matches_type(CapabilityRetrieveResponse, capability, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.capabilities.with_raw_response.retrieve(
+ "bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ capability = await response.parse()
+ assert_matches_type(CapabilityRetrieveResponse, capability, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.capabilities.with_streaming_response.retrieve(
+ "bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ capability = await response.parse()
+ assert_matches_type(CapabilityRetrieveResponse, capability, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.capabilities.with_raw_response.retrieve(
+ "",
+ )
diff --git a/tests/api_resources/matrix/bridges/test_contacts.py b/tests/api_resources/matrix/bridges/test_contacts.py
new file mode 100644
index 0000000..a5e9913
--- /dev/null
+++ b/tests/api_resources/matrix/bridges/test_contacts.py
@@ -0,0 +1,116 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.matrix.bridges import ContactListResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestContacts:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_list(self, client: BeeperDesktop) -> None:
+ contact = client.matrix.bridges.contacts.list(
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(ContactListResponse, contact, path=["response"])
+
+ @parametrize
+ def test_method_list_with_all_params(self, client: BeeperDesktop) -> None:
+ contact = client.matrix.bridges.contacts.list(
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ )
+ assert_matches_type(ContactListResponse, contact, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.contacts.with_raw_response.list(
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ contact = response.parse()
+ assert_matches_type(ContactListResponse, contact, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.contacts.with_streaming_response.list(
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ contact = response.parse()
+ assert_matches_type(ContactListResponse, contact, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.contacts.with_raw_response.list(
+ bridge_id="",
+ )
+
+
+class TestAsyncContacts:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncBeeperDesktop) -> None:
+ contact = await async_client.matrix.bridges.contacts.list(
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(ContactListResponse, contact, path=["response"])
+
+ @parametrize
+ async def test_method_list_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ contact = await async_client.matrix.bridges.contacts.list(
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ )
+ assert_matches_type(ContactListResponse, contact, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.contacts.with_raw_response.list(
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ contact = await response.parse()
+ assert_matches_type(ContactListResponse, contact, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.contacts.with_streaming_response.list(
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ contact = await response.parse()
+ assert_matches_type(ContactListResponse, contact, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.contacts.with_raw_response.list(
+ bridge_id="",
+ )
diff --git a/tests/api_resources/matrix/bridges/test_rooms.py b/tests/api_resources/matrix/bridges/test_rooms.py
new file mode 100644
index 0000000..d637533
--- /dev/null
+++ b/tests/api_resources/matrix/bridges/test_rooms.py
@@ -0,0 +1,279 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.matrix.bridges import (
+ RoomCreateDmResponse,
+ RoomCreateGroupResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestRooms:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create_dm(self, client: BeeperDesktop) -> None:
+ room = client.matrix.bridges.rooms.create_dm(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(RoomCreateDmResponse, room, path=["response"])
+
+ @parametrize
+ def test_method_create_dm_with_all_params(self, client: BeeperDesktop) -> None:
+ room = client.matrix.bridges.rooms.create_dm(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ )
+ assert_matches_type(RoomCreateDmResponse, room, path=["response"])
+
+ @parametrize
+ def test_raw_response_create_dm(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.rooms.with_raw_response.create_dm(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = response.parse()
+ assert_matches_type(RoomCreateDmResponse, room, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create_dm(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.rooms.with_streaming_response.create_dm(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = response.parse()
+ assert_matches_type(RoomCreateDmResponse, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_create_dm(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.rooms.with_raw_response.create_dm(
+ identifier="identifier",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `identifier` but received ''"):
+ client.matrix.bridges.rooms.with_raw_response.create_dm(
+ identifier="",
+ bridge_id="bridgeID",
+ )
+
+ @parametrize
+ def test_method_create_group(self, client: BeeperDesktop) -> None:
+ room = client.matrix.bridges.rooms.create_group(
+ group_type="groupType",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(RoomCreateGroupResponse, room, path=["response"])
+
+ @parametrize
+ def test_method_create_group_with_all_params(self, client: BeeperDesktop) -> None:
+ room = client.matrix.bridges.rooms.create_group(
+ group_type="groupType",
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ avatar={"url": "url"},
+ disappear={
+ "timer": 0,
+ "type": "type",
+ },
+ name={"name": "name"},
+ parent={},
+ participants=["string"],
+ room_id="room_id",
+ topic={"topic": "topic"},
+ type="channel",
+ username="username",
+ )
+ assert_matches_type(RoomCreateGroupResponse, room, path=["response"])
+
+ @parametrize
+ def test_raw_response_create_group(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.rooms.with_raw_response.create_group(
+ group_type="groupType",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = response.parse()
+ assert_matches_type(RoomCreateGroupResponse, room, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create_group(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.rooms.with_streaming_response.create_group(
+ group_type="groupType",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = response.parse()
+ assert_matches_type(RoomCreateGroupResponse, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_create_group(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.rooms.with_raw_response.create_group(
+ group_type="groupType",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_type` but received ''"):
+ client.matrix.bridges.rooms.with_raw_response.create_group(
+ group_type="",
+ bridge_id="bridgeID",
+ )
+
+
+class TestAsyncRooms:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create_dm(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.bridges.rooms.create_dm(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(RoomCreateDmResponse, room, path=["response"])
+
+ @parametrize
+ async def test_method_create_dm_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.bridges.rooms.create_dm(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ )
+ assert_matches_type(RoomCreateDmResponse, room, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create_dm(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.rooms.with_raw_response.create_dm(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = await response.parse()
+ assert_matches_type(RoomCreateDmResponse, room, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create_dm(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.rooms.with_streaming_response.create_dm(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = await response.parse()
+ assert_matches_type(RoomCreateDmResponse, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_create_dm(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.rooms.with_raw_response.create_dm(
+ identifier="identifier",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `identifier` but received ''"):
+ await async_client.matrix.bridges.rooms.with_raw_response.create_dm(
+ identifier="",
+ bridge_id="bridgeID",
+ )
+
+ @parametrize
+ async def test_method_create_group(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.bridges.rooms.create_group(
+ group_type="groupType",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(RoomCreateGroupResponse, room, path=["response"])
+
+ @parametrize
+ async def test_method_create_group_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.bridges.rooms.create_group(
+ group_type="groupType",
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ avatar={"url": "url"},
+ disappear={
+ "timer": 0,
+ "type": "type",
+ },
+ name={"name": "name"},
+ parent={},
+ participants=["string"],
+ room_id="room_id",
+ topic={"topic": "topic"},
+ type="channel",
+ username="username",
+ )
+ assert_matches_type(RoomCreateGroupResponse, room, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create_group(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.rooms.with_raw_response.create_group(
+ group_type="groupType",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = await response.parse()
+ assert_matches_type(RoomCreateGroupResponse, room, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create_group(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.rooms.with_streaming_response.create_group(
+ group_type="groupType",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = await response.parse()
+ assert_matches_type(RoomCreateGroupResponse, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_create_group(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.rooms.with_raw_response.create_group(
+ group_type="groupType",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `group_type` but received ''"):
+ await async_client.matrix.bridges.rooms.with_raw_response.create_group(
+ group_type="",
+ bridge_id="bridgeID",
+ )
diff --git a/tests/api_resources/matrix/bridges/test_users.py b/tests/api_resources/matrix/bridges/test_users.py
new file mode 100644
index 0000000..2e6e69d
--- /dev/null
+++ b/tests/api_resources/matrix/bridges/test_users.py
@@ -0,0 +1,235 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.matrix.bridges import (
+ UserSearchResponse,
+ UserResolveResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestUsers:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_resolve(self, client: BeeperDesktop) -> None:
+ user = client.matrix.bridges.users.resolve(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(UserResolveResponse, user, path=["response"])
+
+ @parametrize
+ def test_method_resolve_with_all_params(self, client: BeeperDesktop) -> None:
+ user = client.matrix.bridges.users.resolve(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ )
+ assert_matches_type(UserResolveResponse, user, path=["response"])
+
+ @parametrize
+ def test_raw_response_resolve(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.users.with_raw_response.resolve(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ user = response.parse()
+ assert_matches_type(UserResolveResponse, user, path=["response"])
+
+ @parametrize
+ def test_streaming_response_resolve(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.users.with_streaming_response.resolve(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ user = response.parse()
+ assert_matches_type(UserResolveResponse, user, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_resolve(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.users.with_raw_response.resolve(
+ identifier="identifier",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `identifier` but received ''"):
+ client.matrix.bridges.users.with_raw_response.resolve(
+ identifier="",
+ bridge_id="bridgeID",
+ )
+
+ @parametrize
+ def test_method_search(self, client: BeeperDesktop) -> None:
+ user = client.matrix.bridges.users.search(
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(UserSearchResponse, user, path=["response"])
+
+ @parametrize
+ def test_method_search_with_all_params(self, client: BeeperDesktop) -> None:
+ user = client.matrix.bridges.users.search(
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ query="query",
+ )
+ assert_matches_type(UserSearchResponse, user, path=["response"])
+
+ @parametrize
+ def test_raw_response_search(self, client: BeeperDesktop) -> None:
+ response = client.matrix.bridges.users.with_raw_response.search(
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ user = response.parse()
+ assert_matches_type(UserSearchResponse, user, path=["response"])
+
+ @parametrize
+ def test_streaming_response_search(self, client: BeeperDesktop) -> None:
+ with client.matrix.bridges.users.with_streaming_response.search(
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ user = response.parse()
+ assert_matches_type(UserSearchResponse, user, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_search(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ client.matrix.bridges.users.with_raw_response.search(
+ bridge_id="",
+ )
+
+
+class TestAsyncUsers:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_resolve(self, async_client: AsyncBeeperDesktop) -> None:
+ user = await async_client.matrix.bridges.users.resolve(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(UserResolveResponse, user, path=["response"])
+
+ @parametrize
+ async def test_method_resolve_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ user = await async_client.matrix.bridges.users.resolve(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ )
+ assert_matches_type(UserResolveResponse, user, path=["response"])
+
+ @parametrize
+ async def test_raw_response_resolve(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.users.with_raw_response.resolve(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ user = await response.parse()
+ assert_matches_type(UserResolveResponse, user, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_resolve(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.users.with_streaming_response.resolve(
+ identifier="identifier",
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ user = await response.parse()
+ assert_matches_type(UserResolveResponse, user, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_resolve(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.users.with_raw_response.resolve(
+ identifier="identifier",
+ bridge_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `identifier` but received ''"):
+ await async_client.matrix.bridges.users.with_raw_response.resolve(
+ identifier="",
+ bridge_id="bridgeID",
+ )
+
+ @parametrize
+ async def test_method_search(self, async_client: AsyncBeeperDesktop) -> None:
+ user = await async_client.matrix.bridges.users.search(
+ bridge_id="bridgeID",
+ )
+ assert_matches_type(UserSearchResponse, user, path=["response"])
+
+ @parametrize
+ async def test_method_search_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ user = await async_client.matrix.bridges.users.search(
+ bridge_id="bridgeID",
+ login_id="bcc68892-b180-414f-9516-b4aadf7d0496",
+ query="query",
+ )
+ assert_matches_type(UserSearchResponse, user, path=["response"])
+
+ @parametrize
+ async def test_raw_response_search(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.bridges.users.with_raw_response.search(
+ bridge_id="bridgeID",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ user = await response.parse()
+ assert_matches_type(UserSearchResponse, user, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_search(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.bridges.users.with_streaming_response.search(
+ bridge_id="bridgeID",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ user = await response.parse()
+ assert_matches_type(UserSearchResponse, user, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_search(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `bridge_id` but received ''"):
+ await async_client.matrix.bridges.users.with_raw_response.search(
+ bridge_id="",
+ )
diff --git a/tests/api_resources/matrix/rooms/__init__.py b/tests/api_resources/matrix/rooms/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /dev/null
+++ b/tests/api_resources/matrix/rooms/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/matrix/rooms/test_account_data.py b/tests/api_resources/matrix/rooms/test_account_data.py
new file mode 100644
index 0000000..913996c
--- /dev/null
+++ b/tests/api_resources/matrix/rooms/test_account_data.py
@@ -0,0 +1,275 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestAccountData:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: BeeperDesktop) -> None:
+ account_data = client.matrix.rooms.account_data.retrieve(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ )
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: BeeperDesktop) -> None:
+ response = client.matrix.rooms.account_data.with_raw_response.retrieve(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_data = response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: BeeperDesktop) -> None:
+ with client.matrix.rooms.account_data.with_streaming_response.retrieve(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_data = response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ client.matrix.rooms.account_data.with_raw_response.retrieve(
+ type="org.example.custom.room.config",
+ user_id="",
+ room_id="!726s6s6q:example.com",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ client.matrix.rooms.account_data.with_raw_response.retrieve(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `type` but received ''"):
+ client.matrix.rooms.account_data.with_raw_response.retrieve(
+ type="",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ )
+
+ @parametrize
+ def test_method_update(self, client: BeeperDesktop) -> None:
+ account_data = client.matrix.rooms.account_data.update(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: BeeperDesktop) -> None:
+ response = client.matrix.rooms.account_data.with_raw_response.update(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_data = response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: BeeperDesktop) -> None:
+ with client.matrix.rooms.account_data.with_streaming_response.update(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_data = response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_update(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ client.matrix.rooms.account_data.with_raw_response.update(
+ type="org.example.custom.room.config",
+ user_id="",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ client.matrix.rooms.account_data.with_raw_response.update(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `type` but received ''"):
+ client.matrix.rooms.account_data.with_raw_response.update(
+ type="",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
+
+
+class TestAsyncAccountData:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ account_data = await async_client.matrix.rooms.account_data.retrieve(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ )
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.rooms.account_data.with_raw_response.retrieve(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_data = await response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.rooms.account_data.with_streaming_response.retrieve(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_data = await response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ await async_client.matrix.rooms.account_data.with_raw_response.retrieve(
+ type="org.example.custom.room.config",
+ user_id="",
+ room_id="!726s6s6q:example.com",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ await async_client.matrix.rooms.account_data.with_raw_response.retrieve(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `type` but received ''"):
+ await async_client.matrix.rooms.account_data.with_raw_response.retrieve(
+ type="",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ )
+
+ @parametrize
+ async def test_method_update(self, async_client: AsyncBeeperDesktop) -> None:
+ account_data = await async_client.matrix.rooms.account_data.update(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.rooms.account_data.with_raw_response.update(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_data = await response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.rooms.account_data.with_streaming_response.update(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_data = await response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ await async_client.matrix.rooms.account_data.with_raw_response.update(
+ type="org.example.custom.room.config",
+ user_id="",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ await async_client.matrix.rooms.account_data.with_raw_response.update(
+ type="org.example.custom.room.config",
+ user_id="@alice:example.com",
+ room_id="",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `type` but received ''"):
+ await async_client.matrix.rooms.account_data.with_raw_response.update(
+ type="",
+ user_id="@alice:example.com",
+ room_id="!726s6s6q:example.com",
+ body={"custom_account_data_key": "custom_account_data_value"},
+ )
diff --git a/tests/api_resources/matrix/rooms/test_events.py b/tests/api_resources/matrix/rooms/test_events.py
new file mode 100644
index 0000000..4610a72
--- /dev/null
+++ b/tests/api_resources/matrix/rooms/test_events.py
@@ -0,0 +1,120 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.matrix.rooms import EventRetrieveResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestEvents:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: BeeperDesktop) -> None:
+ event = client.matrix.rooms.events.retrieve(
+ event_id="$asfDuShaf7Gafaw:matrix.org",
+ room_id="!636q39766251:matrix.org",
+ )
+ assert_matches_type(EventRetrieveResponse, event, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: BeeperDesktop) -> None:
+ response = client.matrix.rooms.events.with_raw_response.retrieve(
+ event_id="$asfDuShaf7Gafaw:matrix.org",
+ room_id="!636q39766251:matrix.org",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ event = response.parse()
+ assert_matches_type(EventRetrieveResponse, event, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: BeeperDesktop) -> None:
+ with client.matrix.rooms.events.with_streaming_response.retrieve(
+ event_id="$asfDuShaf7Gafaw:matrix.org",
+ room_id="!636q39766251:matrix.org",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ event = response.parse()
+ assert_matches_type(EventRetrieveResponse, event, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ client.matrix.rooms.events.with_raw_response.retrieve(
+ event_id="$asfDuShaf7Gafaw:matrix.org",
+ room_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `event_id` but received ''"):
+ client.matrix.rooms.events.with_raw_response.retrieve(
+ event_id="",
+ room_id="!636q39766251:matrix.org",
+ )
+
+
+class TestAsyncEvents:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ event = await async_client.matrix.rooms.events.retrieve(
+ event_id="$asfDuShaf7Gafaw:matrix.org",
+ room_id="!636q39766251:matrix.org",
+ )
+ assert_matches_type(EventRetrieveResponse, event, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.rooms.events.with_raw_response.retrieve(
+ event_id="$asfDuShaf7Gafaw:matrix.org",
+ room_id="!636q39766251:matrix.org",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ event = await response.parse()
+ assert_matches_type(EventRetrieveResponse, event, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.rooms.events.with_streaming_response.retrieve(
+ event_id="$asfDuShaf7Gafaw:matrix.org",
+ room_id="!636q39766251:matrix.org",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ event = await response.parse()
+ assert_matches_type(EventRetrieveResponse, event, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ await async_client.matrix.rooms.events.with_raw_response.retrieve(
+ event_id="$asfDuShaf7Gafaw:matrix.org",
+ room_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `event_id` but received ''"):
+ await async_client.matrix.rooms.events.with_raw_response.retrieve(
+ event_id="",
+ room_id="!636q39766251:matrix.org",
+ )
diff --git a/tests/api_resources/matrix/rooms/test_state.py b/tests/api_resources/matrix/rooms/test_state.py
new file mode 100644
index 0000000..8749cff
--- /dev/null
+++ b/tests/api_resources/matrix/rooms/test_state.py
@@ -0,0 +1,240 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.matrix.rooms import StateListResponse, StateRetrieveResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestState:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: BeeperDesktop) -> None:
+ state = client.matrix.rooms.state.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ )
+ assert_matches_type(StateRetrieveResponse, state, path=["response"])
+
+ @parametrize
+ def test_method_retrieve_with_all_params(self, client: BeeperDesktop) -> None:
+ state = client.matrix.rooms.state.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ format="content",
+ )
+ assert_matches_type(StateRetrieveResponse, state, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: BeeperDesktop) -> None:
+ response = client.matrix.rooms.state.with_raw_response.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = response.parse()
+ assert_matches_type(StateRetrieveResponse, state, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: BeeperDesktop) -> None:
+ with client.matrix.rooms.state.with_streaming_response.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = response.parse()
+ assert_matches_type(StateRetrieveResponse, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ client.matrix.rooms.state.with_raw_response.retrieve(
+ state_key="state_key",
+ room_id="",
+ event_type="m.room.name",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `event_type` but received ''"):
+ client.matrix.rooms.state.with_raw_response.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `state_key` but received ''"):
+ client.matrix.rooms.state.with_raw_response.retrieve(
+ state_key="",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ )
+
+ @parametrize
+ def test_method_list(self, client: BeeperDesktop) -> None:
+ state = client.matrix.rooms.state.list(
+ "!636q39766251:example.com",
+ )
+ assert_matches_type(StateListResponse, state, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: BeeperDesktop) -> None:
+ response = client.matrix.rooms.state.with_raw_response.list(
+ "!636q39766251:example.com",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = response.parse()
+ assert_matches_type(StateListResponse, state, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: BeeperDesktop) -> None:
+ with client.matrix.rooms.state.with_streaming_response.list(
+ "!636q39766251:example.com",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = response.parse()
+ assert_matches_type(StateListResponse, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_list(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ client.matrix.rooms.state.with_raw_response.list(
+ "",
+ )
+
+
+class TestAsyncState:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ state = await async_client.matrix.rooms.state.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ )
+ assert_matches_type(StateRetrieveResponse, state, path=["response"])
+
+ @parametrize
+ async def test_method_retrieve_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ state = await async_client.matrix.rooms.state.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ format="content",
+ )
+ assert_matches_type(StateRetrieveResponse, state, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.rooms.state.with_raw_response.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = await response.parse()
+ assert_matches_type(StateRetrieveResponse, state, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.rooms.state.with_streaming_response.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = await response.parse()
+ assert_matches_type(StateRetrieveResponse, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ await async_client.matrix.rooms.state.with_raw_response.retrieve(
+ state_key="state_key",
+ room_id="",
+ event_type="m.room.name",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `event_type` but received ''"):
+ await async_client.matrix.rooms.state.with_raw_response.retrieve(
+ state_key="state_key",
+ room_id="!636q39766251:example.com",
+ event_type="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `state_key` but received ''"):
+ await async_client.matrix.rooms.state.with_raw_response.retrieve(
+ state_key="",
+ room_id="!636q39766251:example.com",
+ event_type="m.room.name",
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncBeeperDesktop) -> None:
+ state = await async_client.matrix.rooms.state.list(
+ "!636q39766251:example.com",
+ )
+ assert_matches_type(StateListResponse, state, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.rooms.state.with_raw_response.list(
+ "!636q39766251:example.com",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ state = await response.parse()
+ assert_matches_type(StateListResponse, state, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.rooms.state.with_streaming_response.list(
+ "!636q39766251:example.com",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ state = await response.parse()
+ assert_matches_type(StateListResponse, state, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_list(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ await async_client.matrix.rooms.state.with_raw_response.list(
+ "",
+ )
diff --git a/tests/api_resources/matrix/test_rooms.py b/tests/api_resources/matrix/test_rooms.py
new file mode 100644
index 0000000..6c9f5a1
--- /dev/null
+++ b/tests/api_resources/matrix/test_rooms.py
@@ -0,0 +1,337 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.matrix import (
+ RoomJoinResponse,
+ RoomCreateResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestRooms:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_create(self, client: BeeperDesktop) -> None:
+ room = client.matrix.rooms.create()
+ assert_matches_type(RoomCreateResponse, room, path=["response"])
+
+ @parametrize
+ def test_method_create_with_all_params(self, client: BeeperDesktop) -> None:
+ room = client.matrix.rooms.create(
+ creation_content={"m.federate": False},
+ initial_state=[
+ {
+ "content": {},
+ "type": "type",
+ "state_key": "state_key",
+ }
+ ],
+ invite=["string"],
+ invite_3pid=[
+ {
+ "address": "cheeky@monkey.com",
+ "id_access_token": "abc123_OpaqueString",
+ "id_server": "matrix.org",
+ "medium": "email",
+ }
+ ],
+ is_direct=True,
+ name="The Grand Duke Pub",
+ power_level_content_override={},
+ preset="public_chat",
+ room_alias_name="thepub",
+ room_version="1",
+ topic="All about happy hour",
+ visibility="public",
+ )
+ assert_matches_type(RoomCreateResponse, room, path=["response"])
+
+ @parametrize
+ def test_raw_response_create(self, client: BeeperDesktop) -> None:
+ response = client.matrix.rooms.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = response.parse()
+ assert_matches_type(RoomCreateResponse, room, path=["response"])
+
+ @parametrize
+ def test_streaming_response_create(self, client: BeeperDesktop) -> None:
+ with client.matrix.rooms.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = response.parse()
+ assert_matches_type(RoomCreateResponse, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_method_join(self, client: BeeperDesktop) -> None:
+ room = client.matrix.rooms.join(
+ room_id_or_alias="!monkeys:matrix.org",
+ )
+ assert_matches_type(RoomJoinResponse, room, path=["response"])
+
+ @parametrize
+ def test_method_join_with_all_params(self, client: BeeperDesktop) -> None:
+ room = client.matrix.rooms.join(
+ room_id_or_alias="!monkeys:matrix.org",
+ via=["string"],
+ reason="Looking for support",
+ third_party_signed={
+ "token": "random8nonce",
+ "mxid": "bob",
+ "sender": "alice",
+ "signatures": {"example.org": {"ed25519:0": "some9signature"}},
+ },
+ )
+ assert_matches_type(RoomJoinResponse, room, path=["response"])
+
+ @parametrize
+ def test_raw_response_join(self, client: BeeperDesktop) -> None:
+ response = client.matrix.rooms.with_raw_response.join(
+ room_id_or_alias="!monkeys:matrix.org",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = response.parse()
+ assert_matches_type(RoomJoinResponse, room, path=["response"])
+
+ @parametrize
+ def test_streaming_response_join(self, client: BeeperDesktop) -> None:
+ with client.matrix.rooms.with_streaming_response.join(
+ room_id_or_alias="!monkeys:matrix.org",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = response.parse()
+ assert_matches_type(RoomJoinResponse, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_join(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id_or_alias` but received ''"):
+ client.matrix.rooms.with_raw_response.join(
+ room_id_or_alias="",
+ )
+
+ @parametrize
+ def test_method_leave(self, client: BeeperDesktop) -> None:
+ room = client.matrix.rooms.leave(
+ room_id="!nkl290a:matrix.org",
+ )
+ assert_matches_type(object, room, path=["response"])
+
+ @parametrize
+ def test_method_leave_with_all_params(self, client: BeeperDesktop) -> None:
+ room = client.matrix.rooms.leave(
+ room_id="!nkl290a:matrix.org",
+ reason="Saying farewell - thanks for the support!",
+ )
+ assert_matches_type(object, room, path=["response"])
+
+ @parametrize
+ def test_raw_response_leave(self, client: BeeperDesktop) -> None:
+ response = client.matrix.rooms.with_raw_response.leave(
+ room_id="!nkl290a:matrix.org",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = response.parse()
+ assert_matches_type(object, room, path=["response"])
+
+ @parametrize
+ def test_streaming_response_leave(self, client: BeeperDesktop) -> None:
+ with client.matrix.rooms.with_streaming_response.leave(
+ room_id="!nkl290a:matrix.org",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = response.parse()
+ assert_matches_type(object, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_leave(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ client.matrix.rooms.with_raw_response.leave(
+ room_id="",
+ )
+
+
+class TestAsyncRooms:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_create(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.rooms.create()
+ assert_matches_type(RoomCreateResponse, room, path=["response"])
+
+ @parametrize
+ async def test_method_create_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.rooms.create(
+ creation_content={"m.federate": False},
+ initial_state=[
+ {
+ "content": {},
+ "type": "type",
+ "state_key": "state_key",
+ }
+ ],
+ invite=["string"],
+ invite_3pid=[
+ {
+ "address": "cheeky@monkey.com",
+ "id_access_token": "abc123_OpaqueString",
+ "id_server": "matrix.org",
+ "medium": "email",
+ }
+ ],
+ is_direct=True,
+ name="The Grand Duke Pub",
+ power_level_content_override={},
+ preset="public_chat",
+ room_alias_name="thepub",
+ room_version="1",
+ topic="All about happy hour",
+ visibility="public",
+ )
+ assert_matches_type(RoomCreateResponse, room, path=["response"])
+
+ @parametrize
+ async def test_raw_response_create(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.rooms.with_raw_response.create()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = await response.parse()
+ assert_matches_type(RoomCreateResponse, room, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_create(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.rooms.with_streaming_response.create() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = await response.parse()
+ assert_matches_type(RoomCreateResponse, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_method_join(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.rooms.join(
+ room_id_or_alias="!monkeys:matrix.org",
+ )
+ assert_matches_type(RoomJoinResponse, room, path=["response"])
+
+ @parametrize
+ async def test_method_join_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.rooms.join(
+ room_id_or_alias="!monkeys:matrix.org",
+ via=["string"],
+ reason="Looking for support",
+ third_party_signed={
+ "token": "random8nonce",
+ "mxid": "bob",
+ "sender": "alice",
+ "signatures": {"example.org": {"ed25519:0": "some9signature"}},
+ },
+ )
+ assert_matches_type(RoomJoinResponse, room, path=["response"])
+
+ @parametrize
+ async def test_raw_response_join(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.rooms.with_raw_response.join(
+ room_id_or_alias="!monkeys:matrix.org",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = await response.parse()
+ assert_matches_type(RoomJoinResponse, room, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_join(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.rooms.with_streaming_response.join(
+ room_id_or_alias="!monkeys:matrix.org",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = await response.parse()
+ assert_matches_type(RoomJoinResponse, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_join(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id_or_alias` but received ''"):
+ await async_client.matrix.rooms.with_raw_response.join(
+ room_id_or_alias="",
+ )
+
+ @parametrize
+ async def test_method_leave(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.rooms.leave(
+ room_id="!nkl290a:matrix.org",
+ )
+ assert_matches_type(object, room, path=["response"])
+
+ @parametrize
+ async def test_method_leave_with_all_params(self, async_client: AsyncBeeperDesktop) -> None:
+ room = await async_client.matrix.rooms.leave(
+ room_id="!nkl290a:matrix.org",
+ reason="Saying farewell - thanks for the support!",
+ )
+ assert_matches_type(object, room, path=["response"])
+
+ @parametrize
+ async def test_raw_response_leave(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.rooms.with_raw_response.leave(
+ room_id="!nkl290a:matrix.org",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ room = await response.parse()
+ assert_matches_type(object, room, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_leave(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.rooms.with_streaming_response.leave(
+ room_id="!nkl290a:matrix.org",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ room = await response.parse()
+ assert_matches_type(object, room, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_leave(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `room_id` but received ''"):
+ await async_client.matrix.rooms.with_raw_response.leave(
+ room_id="",
+ )
diff --git a/tests/api_resources/matrix/test_users.py b/tests/api_resources/matrix/test_users.py
new file mode 100644
index 0000000..5b148a2
--- /dev/null
+++ b/tests/api_resources/matrix/test_users.py
@@ -0,0 +1,100 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types.matrix import UserRetrieveProfileResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestUsers:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve_profile(self, client: BeeperDesktop) -> None:
+ user = client.matrix.users.retrieve_profile(
+ "@alice:example.com",
+ )
+ assert_matches_type(UserRetrieveProfileResponse, user, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve_profile(self, client: BeeperDesktop) -> None:
+ response = client.matrix.users.with_raw_response.retrieve_profile(
+ "@alice:example.com",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ user = response.parse()
+ assert_matches_type(UserRetrieveProfileResponse, user, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve_profile(self, client: BeeperDesktop) -> None:
+ with client.matrix.users.with_streaming_response.retrieve_profile(
+ "@alice:example.com",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ user = response.parse()
+ assert_matches_type(UserRetrieveProfileResponse, user, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve_profile(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ client.matrix.users.with_raw_response.retrieve_profile(
+ "",
+ )
+
+
+class TestAsyncUsers:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve_profile(self, async_client: AsyncBeeperDesktop) -> None:
+ user = await async_client.matrix.users.retrieve_profile(
+ "@alice:example.com",
+ )
+ assert_matches_type(UserRetrieveProfileResponse, user, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve_profile(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.users.with_raw_response.retrieve_profile(
+ "@alice:example.com",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ user = await response.parse()
+ assert_matches_type(UserRetrieveProfileResponse, user, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve_profile(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.users.with_streaming_response.retrieve_profile(
+ "@alice:example.com",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ user = await response.parse()
+ assert_matches_type(UserRetrieveProfileResponse, user, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve_profile(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ await async_client.matrix.users.with_raw_response.retrieve_profile(
+ "",
+ )
diff --git a/tests/api_resources/matrix/users/__init__.py b/tests/api_resources/matrix/users/__init__.py
new file mode 100644
index 0000000..fd8019a
--- /dev/null
+++ b/tests/api_resources/matrix/users/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/matrix/users/test_account_data.py b/tests/api_resources/matrix/users/test_account_data.py
new file mode 100644
index 0000000..4e31b87
--- /dev/null
+++ b/tests/api_resources/matrix/users/test_account_data.py
@@ -0,0 +1,225 @@
+# 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 tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestAccountData:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: BeeperDesktop) -> None:
+ account_data = client.matrix.users.account_data.retrieve(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ )
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: BeeperDesktop) -> None:
+ response = client.matrix.users.account_data.with_raw_response.retrieve(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_data = response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: BeeperDesktop) -> None:
+ with client.matrix.users.account_data.with_streaming_response.retrieve(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_data = response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ client.matrix.users.account_data.with_raw_response.retrieve(
+ type="org.example.custom.config",
+ user_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `type` but received ''"):
+ client.matrix.users.account_data.with_raw_response.retrieve(
+ type="",
+ user_id="@alice:example.com",
+ )
+
+ @parametrize
+ def test_method_update(self, client: BeeperDesktop) -> None:
+ account_data = client.matrix.users.account_data.update(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ body={"custom_account_data_key": "custom_config_value"},
+ )
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ def test_raw_response_update(self, client: BeeperDesktop) -> None:
+ response = client.matrix.users.account_data.with_raw_response.update(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ body={"custom_account_data_key": "custom_config_value"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_data = response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ def test_streaming_response_update(self, client: BeeperDesktop) -> None:
+ with client.matrix.users.account_data.with_streaming_response.update(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ body={"custom_account_data_key": "custom_config_value"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_data = response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_update(self, client: BeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ client.matrix.users.account_data.with_raw_response.update(
+ type="org.example.custom.config",
+ user_id="",
+ body={"custom_account_data_key": "custom_config_value"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `type` but received ''"):
+ client.matrix.users.account_data.with_raw_response.update(
+ type="",
+ user_id="@alice:example.com",
+ body={"custom_account_data_key": "custom_config_value"},
+ )
+
+
+class TestAsyncAccountData:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ account_data = await async_client.matrix.users.account_data.retrieve(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ )
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.users.account_data.with_raw_response.retrieve(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_data = await response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.users.account_data.with_streaming_response.retrieve(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_data = await response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ await async_client.matrix.users.account_data.with_raw_response.retrieve(
+ type="org.example.custom.config",
+ user_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `type` but received ''"):
+ await async_client.matrix.users.account_data.with_raw_response.retrieve(
+ type="",
+ user_id="@alice:example.com",
+ )
+
+ @parametrize
+ async def test_method_update(self, async_client: AsyncBeeperDesktop) -> None:
+ account_data = await async_client.matrix.users.account_data.update(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ body={"custom_account_data_key": "custom_config_value"},
+ )
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ async def test_raw_response_update(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.matrix.users.account_data.with_raw_response.update(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ body={"custom_account_data_key": "custom_config_value"},
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ account_data = await response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_update(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.matrix.users.account_data.with_streaming_response.update(
+ type="org.example.custom.config",
+ user_id="@alice:example.com",
+ body={"custom_account_data_key": "custom_config_value"},
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ account_data = await response.parse()
+ assert_matches_type(object, account_data, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_update(self, async_client: AsyncBeeperDesktop) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `user_id` but received ''"):
+ await async_client.matrix.users.account_data.with_raw_response.update(
+ type="org.example.custom.config",
+ user_id="",
+ body={"custom_account_data_key": "custom_config_value"},
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `type` but received ''"):
+ await async_client.matrix.users.account_data.with_raw_response.update(
+ type="",
+ user_id="@alice:example.com",
+ body={"custom_account_data_key": "custom_config_value"},
+ )
diff --git a/tests/api_resources/test_app.py b/tests/api_resources/test_app.py
new file mode 100644
index 0000000..ff78bb6
--- /dev/null
+++ b/tests/api_resources/test_app.py
@@ -0,0 +1,74 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types import AppStatusResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestApp:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_status(self, client: BeeperDesktop) -> None:
+ app = client.app.status()
+ assert_matches_type(AppStatusResponse, app, path=["response"])
+
+ @parametrize
+ def test_raw_response_status(self, client: BeeperDesktop) -> None:
+ response = client.app.with_raw_response.status()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = response.parse()
+ assert_matches_type(AppStatusResponse, app, path=["response"])
+
+ @parametrize
+ def test_streaming_response_status(self, client: BeeperDesktop) -> None:
+ with client.app.with_streaming_response.status() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = response.parse()
+ assert_matches_type(AppStatusResponse, app, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncApp:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_status(self, async_client: AsyncBeeperDesktop) -> None:
+ app = await async_client.app.status()
+ assert_matches_type(AppStatusResponse, app, path=["response"])
+
+ @parametrize
+ async def test_raw_response_status(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.app.with_raw_response.status()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ app = await response.parse()
+ assert_matches_type(AppStatusResponse, app, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_status(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.app.with_streaming_response.status() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ app = await response.parse()
+ assert_matches_type(AppStatusResponse, app, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_bridges.py b/tests/api_resources/test_bridges.py
new file mode 100644
index 0000000..f5af604
--- /dev/null
+++ b/tests/api_resources/test_bridges.py
@@ -0,0 +1,74 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from tests.utils import assert_matches_type
+from beeper_desktop_api import BeeperDesktop, AsyncBeeperDesktop
+from beeper_desktop_api.types import BridgeListResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestBridges:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_list(self, client: BeeperDesktop) -> None:
+ bridge = client.bridges.list()
+ assert_matches_type(BridgeListResponse, bridge, path=["response"])
+
+ @parametrize
+ def test_raw_response_list(self, client: BeeperDesktop) -> None:
+ response = client.bridges.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ bridge = response.parse()
+ assert_matches_type(BridgeListResponse, bridge, path=["response"])
+
+ @parametrize
+ def test_streaming_response_list(self, client: BeeperDesktop) -> None:
+ with client.bridges.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ bridge = response.parse()
+ assert_matches_type(BridgeListResponse, bridge, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncBridges:
+ parametrize = pytest.mark.parametrize(
+ "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
+ )
+
+ @parametrize
+ async def test_method_list(self, async_client: AsyncBeeperDesktop) -> None:
+ bridge = await async_client.bridges.list()
+ assert_matches_type(BridgeListResponse, bridge, path=["response"])
+
+ @parametrize
+ async def test_raw_response_list(self, async_client: AsyncBeeperDesktop) -> None:
+ response = await async_client.bridges.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ bridge = await response.parse()
+ assert_matches_type(BridgeListResponse, bridge, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_list(self, async_client: AsyncBeeperDesktop) -> None:
+ async with async_client.bridges.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ bridge = await response.parse()
+ assert_matches_type(BridgeListResponse, bridge, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/test_models.py b/tests/test_models.py
index e71da85..d228ea1 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -1,7 +1,8 @@
import json
-from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional, cast
+from typing import TYPE_CHECKING, Any, Dict, List, Union, Iterable, Optional, cast
from datetime import datetime, timezone
-from typing_extensions import Literal, Annotated, TypeAliasType
+from collections import deque
+from typing_extensions import Literal, Annotated, TypedDict, TypeAliasType
import pytest
import pydantic
@@ -9,7 +10,7 @@
from beeper_desktop_api._utils import PropertyInfo
from beeper_desktop_api._compat import PYDANTIC_V1, parse_obj, model_dump, model_json
-from beeper_desktop_api._models import DISCRIMINATOR_CACHE, BaseModel, construct_type
+from beeper_desktop_api._models import DISCRIMINATOR_CACHE, BaseModel, EagerIterable, construct_type
class BasicModel(BaseModel):
@@ -961,3 +962,56 @@ def __getattr__(self, attr: str) -> Item: ...
assert model.a.prop == 1
assert isinstance(model.a, Item)
assert model.other == "foo"
+
+
+# NOTE: Workaround for Pydantic Iterable behavior.
+# Iterable fields are replaced with a ValidatorIterator and may be consumed
+# during serialization, which can cause subsequent dumps to return empty data.
+# See: https://github.com/pydantic/pydantic/issues/9541
+@pytest.mark.parametrize(
+ "data, expected_validated",
+ [
+ ([1, 2, 3], [1, 2, 3]),
+ ((1, 2, 3), (1, 2, 3)),
+ (set([1, 2, 3]), set([1, 2, 3])),
+ (iter([1, 2, 3]), [1, 2, 3]),
+ ([], []),
+ ((x for x in [1, 2, 3]), [1, 2, 3]),
+ (map(lambda x: x, [1, 2, 3]), [1, 2, 3]),
+ (frozenset([1, 2, 3]), frozenset([1, 2, 3])),
+ (deque([1, 2, 3]), deque([1, 2, 3])),
+ ],
+ ids=["list", "tuple", "set", "iterator", "empty", "generator", "map", "frozenset", "deque"],
+)
+@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2")
+def test_iterable_construction(data: Iterable[int], expected_validated: Iterable[int]) -> None:
+ class TypeWithIterable(TypedDict):
+ items: EagerIterable[int]
+
+ class Model(BaseModel):
+ data: TypeWithIterable
+
+ m = Model.model_validate({"data": {"items": data}})
+ assert m.data["items"] == expected_validated
+
+ # Verify repeated dumps don't lose data (the original bug)
+ assert m.model_dump()["data"]["items"] == list(expected_validated)
+ assert m.model_dump()["data"]["items"] == list(expected_validated)
+
+
+@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2")
+def test_iterable_construction_str_falls_back_to_list() -> None:
+ # str is iterable (over chars), but str(list_of_chars) produces the list's repr
+ # rather than reconstructing a string from items. We special-case str to fall
+ # back to list instead of attempting reconstruction.
+ class TypeWithIterable(TypedDict):
+ items: EagerIterable[str]
+
+ class Model(BaseModel):
+ data: TypeWithIterable
+
+ m = Model.model_validate({"data": {"items": "hello"}})
+
+ # falls back to list of chars rather than calling str(["h", "e", "l", "l", "o"])
+ assert m.data["items"] == ["h", "e", "l", "l", "o"]
+ assert m.model_dump()["data"]["items"] == ["h", "e", "l", "l", "o"]