diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bd7f384..29102ae 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.2.0" + ".": "4.3.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 50bd7a1..56c368e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 23 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper%2Fbeeper-desktop-api-ee25e67fc85ccc86cedb2ca0865385709877582132103e0afa68d7b43551784a.yml -openapi_spec_hash: d41fd99c9a8645a1fd69c519cd25a637 -config_hash: abdcaeff62a619bdf25d727cdeacf3b0 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper%2Fbeeper-desktop-api-4acef56b00be513f305543096fdd407e6947f0a5ad268ab2e627ff30b37a75db.yml +openapi_spec_hash: e876d796b6c25f18577f6be3944bf7d9 +config_hash: 659111d4e28efa599b5f800619ed79c2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 757844b..d5ee4c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 4.3.0 (2026-02-20) + +Full Changelog: [v4.2.0...v4.3.0](https://github.com/beeper/desktop-api-python/compare/v4.2.0...v4.3.0) + +### Features + +* **api:** api update ([4f6c268](https://github.com/beeper/desktop-api-python/commit/4f6c2685f00a7fd4f1db0b34faa6e354a0f7e220)) +* **api:** api update ([c77412c](https://github.com/beeper/desktop-api-python/commit/c77412c3d4daa460f8901f715a9f59dc1bfa3970)) +* **api:** manual updates ([223108d](https://github.com/beeper/desktop-api-python/commit/223108ddc2f84269df96dd8abf6787d8e45c02e6)) + + +### Chores + +* update mock server docs ([70593f0](https://github.com/beeper/desktop-api-python/commit/70593f0416d4ed7251957c9fcdb5805e570b2577)) +* update SDK settings ([3741b42](https://github.com/beeper/desktop-api-python/commit/3741b42c7ab0c75897bb5cd753b1ce3b323686d2)) + ## 4.2.0 (2026-02-20) Full Changelog: [v4.1.296...v4.2.0](https://github.com/beeper/desktop-api-python/compare/v4.1.296...v4.2.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 81bc94a..08c3ec2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -88,8 +88,7 @@ $ pip install ./path-to-wheel-file.whl Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. ```sh -# you will need npm installed -$ npx prism mock path/to/your/openapi.yml +$ ./scripts/mock ``` ```sh diff --git a/README.md b/README.md index c0c9be9..b42ad75 100644 --- a/README.md +++ b/README.md @@ -218,10 +218,11 @@ from beeper_desktop_api import BeeperDesktop client = BeeperDesktop() -client.chats.reminders.create( - chat_id="!NCdzlIaMjZUmvmvyHU:beeper.com", - reminder={"remind_at_ms": 0}, +chat = client.chats.create( + account_id="accountID", + user={}, ) +print(chat.user) ``` ## File uploads diff --git a/pyproject.toml b/pyproject.toml index 96e553a..089b317 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "beeper_desktop_api" -version = "4.2.0" +version = "4.3.0" description = "The official Python library for the beeperdesktop API" dynamic = ["readme"] license = "MIT" diff --git a/src/beeper_desktop_api/_version.py b/src/beeper_desktop_api/_version.py index 9e1f20a..1bc95e4 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__ = "4.2.0" # x-release-please-version +__version__ = "4.3.0" # x-release-please-version diff --git a/src/beeper_desktop_api/resources/chats/chats.py b/src/beeper_desktop_api/resources/chats/chats.py index 4682744..6a3cdb0 100644 --- a/src/beeper_desktop_api/resources/chats/chats.py +++ b/src/beeper_desktop_api/resources/chats/chats.py @@ -79,7 +79,14 @@ def with_streaming_response(self) -> ChatsResourceWithStreamingResponse: def create( self, *, - chat: chat_create_params.Chat | Omit = omit, + account_id: str, + allow_invite: bool | Omit = omit, + message_text: str | Omit = omit, + mode: Literal["create", "start"] | Omit = omit, + participant_ids: SequenceNotStr[str] | Omit = omit, + title: str | Omit = omit, + type: Literal["single", "group"] | Omit = omit, + user: chat_create_params.User | 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, @@ -92,6 +99,26 @@ def create( user data (mode='start'). Args: + account_id: Account to create or start the chat on. + + allow_invite: Whether invite-based DM creation is allowed when required by the platform. Used + for mode='start'. + + message_text: Optional first message content if the platform requires it to create the chat. + + mode: Operation mode. Defaults to 'create' when omitted. + + participant_ids: Required when mode='create'. User IDs to include in the new chat. + + title: Optional title for group chats when mode='create'; ignored for single chats on + most platforms. + + type: Required when mode='create'. 'single' requires exactly one participantID; + 'group' supports multiple participants and optional title. + + user: Required when mode='start'. Merged user-like contact payload used to resolve the + best identifier. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -102,7 +129,19 @@ def create( """ return self._post( "/v1/chats", - body=maybe_transform(chat, chat_create_params.ChatCreateParams), + body=maybe_transform( + { + "account_id": account_id, + "allow_invite": allow_invite, + "message_text": message_text, + "mode": mode, + "participant_ids": participant_ids, + "title": title, + "type": type, + "user": user, + }, + chat_create_params.ChatCreateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -383,7 +422,14 @@ def with_streaming_response(self) -> AsyncChatsResourceWithStreamingResponse: async def create( self, *, - chat: chat_create_params.Chat | Omit = omit, + account_id: str, + allow_invite: bool | Omit = omit, + message_text: str | Omit = omit, + mode: Literal["create", "start"] | Omit = omit, + participant_ids: SequenceNotStr[str] | Omit = omit, + title: str | Omit = omit, + type: Literal["single", "group"] | Omit = omit, + user: chat_create_params.User | 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, @@ -396,6 +442,26 @@ async def create( user data (mode='start'). Args: + account_id: Account to create or start the chat on. + + allow_invite: Whether invite-based DM creation is allowed when required by the platform. Used + for mode='start'. + + message_text: Optional first message content if the platform requires it to create the chat. + + mode: Operation mode. Defaults to 'create' when omitted. + + participant_ids: Required when mode='create'. User IDs to include in the new chat. + + title: Optional title for group chats when mode='create'; ignored for single chats on + most platforms. + + type: Required when mode='create'. 'single' requires exactly one participantID; + 'group' supports multiple participants and optional title. + + user: Required when mode='start'. Merged user-like contact payload used to resolve the + best identifier. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -406,7 +472,19 @@ async def create( """ return await self._post( "/v1/chats", - body=await async_maybe_transform(chat, chat_create_params.ChatCreateParams), + body=await async_maybe_transform( + { + "account_id": account_id, + "allow_invite": allow_invite, + "message_text": message_text, + "mode": mode, + "participant_ids": participant_ids, + "title": title, + "type": type, + "user": user, + }, + chat_create_params.ChatCreateParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/beeper_desktop_api/resources/messages.py b/src/beeper_desktop_api/resources/messages.py index 63ad8e1..b97c7a0 100644 --- a/src/beeper_desktop_api/resources/messages.py +++ b/src/beeper_desktop_api/resources/messages.py @@ -163,7 +163,7 @@ def search( limit: int | Omit = omit, media_types: List[Literal["any", "video", "image", "link", "file"]] | Omit = omit, query: str | Omit = omit, - sender: Union[Literal["me", "others"], str] | Omit = omit, + sender: 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, @@ -439,7 +439,7 @@ def search( limit: int | Omit = omit, media_types: List[Literal["any", "video", "image", "link", "file"]] | Omit = omit, query: str | Omit = omit, - sender: Union[Literal["me", "others"], str] | Omit = omit, + sender: 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, diff --git a/src/beeper_desktop_api/types/chat_create_params.py b/src/beeper_desktop_api/types/chat_create_params.py index b0314d5..93229c1 100644 --- a/src/beeper_desktop_api/types/chat_create_params.py +++ b/src/beeper_desktop_api/types/chat_create_params.py @@ -2,44 +2,58 @@ from __future__ import annotations -from typing import Union -from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict from .._types import SequenceNotStr from .._utils import PropertyInfo -__all__ = ["ChatCreateParams", "Chat", "ChatUnionMember0", "ChatUnionMember1", "ChatUnionMember1User"] +__all__ = ["ChatCreateParams", "User"] class ChatCreateParams(TypedDict, total=False): - chat: Chat - - -class ChatUnionMember0(TypedDict, total=False): account_id: Required[Annotated[str, PropertyInfo(alias="accountID")]] - """Account to create the chat on.""" + """Account to create or start the chat on.""" - participant_ids: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="participantIDs")]] - """User IDs to include in the new chat.""" + allow_invite: Annotated[bool, PropertyInfo(alias="allowInvite")] + """Whether invite-based DM creation is allowed when required by the platform. - type: Required[Literal["single", "group"]] - """ - Chat type to create: 'single' requires exactly one participantID; 'group' - supports multiple participants and optional title. + Used for mode='start'. """ message_text: Annotated[str, PropertyInfo(alias="messageText")] """Optional first message content if the platform requires it to create the chat.""" - mode: Literal["create"] - """Create mode. Defaults to 'create' when omitted.""" + mode: Literal["create", "start"] + """Operation mode. Defaults to 'create' when omitted.""" + + participant_ids: Annotated[SequenceNotStr[str], PropertyInfo(alias="participantIDs")] + """Required when mode='create'. User IDs to include in the new chat.""" title: str - """Optional title for group chats; ignored for single chats on most platforms.""" + """ + Optional title for group chats when mode='create'; ignored for single chats on + most platforms. + """ + type: Literal["single", "group"] + """Required when mode='create'. -class ChatUnionMember1User(TypedDict, total=False): - """Merged user-like contact payload used to resolve the best identifier.""" + 'single' requires exactly one participantID; 'group' supports multiple + participants and optional title. + """ + + user: User + """Required when mode='start'. + + Merged user-like contact payload used to resolve the best identifier. + """ + + +class User(TypedDict, total=False): + """Required when mode='start'. + + Merged user-like contact payload used to resolve the best identifier. + """ id: str """Known user ID when available.""" @@ -55,23 +69,3 @@ class ChatUnionMember1User(TypedDict, total=False): username: str """Username/handle candidate.""" - - -class ChatUnionMember1(TypedDict, total=False): - account_id: Required[Annotated[str, PropertyInfo(alias="accountID")]] - """Account to start the chat on.""" - - mode: Required[Literal["start"]] - """Start mode for resolving/creating a direct chat from merged contact data.""" - - user: Required[ChatUnionMember1User] - """Merged user-like contact payload used to resolve the best identifier.""" - - allow_invite: Annotated[bool, PropertyInfo(alias="allowInvite")] - """Whether invite-based DM creation is allowed when required by the platform.""" - - message_text: Annotated[str, PropertyInfo(alias="messageText")] - """Optional first message content if the platform requires it to create the chat.""" - - -Chat: TypeAlias = Union[ChatUnionMember0, ChatUnionMember1] diff --git a/src/beeper_desktop_api/types/message_search_params.py b/src/beeper_desktop_api/types/message_search_params.py index 3ba609d..e9bab35 100644 --- a/src/beeper_desktop_api/types/message_search_params.py +++ b/src/beeper_desktop_api/types/message_search_params.py @@ -74,7 +74,7 @@ class MessageSearchParams(TypedDict, total=False): only by other parameters. """ - sender: Union[Literal["me", "others"], str] + sender: str """ Filter by sender: 'me' (messages sent by the authenticated user), 'others' (messages sent by others), or a specific user ID string (user.id). diff --git a/src/beeper_desktop_api/types/shared/error.py b/src/beeper_desktop_api/types/shared/error.py index df9fdbb..17c2409 100644 --- a/src/beeper_desktop_api/types/shared/error.py +++ b/src/beeper_desktop_api/types/shared/error.py @@ -5,10 +5,10 @@ from ..._models import BaseModel -__all__ = ["Error", "Details", "DetailsIssues", "DetailsIssuesIssue"] +__all__ = ["Error", "Details", "DetailsValidationDetails", "DetailsValidationDetailsIssue"] -class DetailsIssuesIssue(BaseModel): +class DetailsValidationDetailsIssue(BaseModel): code: str """Validation issue code""" @@ -19,14 +19,14 @@ class DetailsIssuesIssue(BaseModel): """Path pointing to the invalid field within the payload""" -class DetailsIssues(BaseModel): +class DetailsValidationDetails(BaseModel): """Validation error details""" - issues: List[DetailsIssuesIssue] + issues: List[DetailsValidationDetailsIssue] """List of validation issues""" -Details: TypeAlias = Union[DetailsIssues, Dict[str, Optional[object]], Optional[object]] +Details: TypeAlias = Union[DetailsValidationDetails, Dict[str, Optional[object]], Optional[object]] class Error(BaseModel): diff --git a/tests/api_resources/test_chats.py b/tests/api_resources/test_chats.py index ba28f71..b899add 100644 --- a/tests/api_resources/test_chats.py +++ b/tests/api_resources/test_chats.py @@ -25,26 +25,36 @@ class TestChats: @parametrize def test_method_create(self, client: BeeperDesktop) -> None: - chat = client.chats.create() + chat = client.chats.create( + account_id="accountID", + ) assert_matches_type(ChatCreateResponse, chat, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: BeeperDesktop) -> None: chat = client.chats.create( - chat={ - "account_id": "accountID", - "participant_ids": ["string"], - "type": "single", - "message_text": "messageText", - "mode": "create", - "title": "title", + account_id="accountID", + allow_invite=True, + message_text="messageText", + mode="create", + participant_ids=["string"], + title="title", + type="single", + user={ + "id": "id", + "email": "email", + "full_name": "fullName", + "phone_number": "phoneNumber", + "username": "username", }, ) assert_matches_type(ChatCreateResponse, chat, path=["response"]) @parametrize def test_raw_response_create(self, client: BeeperDesktop) -> None: - response = client.chats.with_raw_response.create() + response = client.chats.with_raw_response.create( + account_id="accountID", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -53,7 +63,9 @@ def test_raw_response_create(self, client: BeeperDesktop) -> None: @parametrize def test_streaming_response_create(self, client: BeeperDesktop) -> None: - with client.chats.with_streaming_response.create() as response: + with client.chats.with_streaming_response.create( + account_id="accountID", + ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -245,26 +257,36 @@ class TestAsyncChats: @parametrize async def test_method_create(self, async_client: AsyncBeeperDesktop) -> None: - chat = await async_client.chats.create() + chat = await async_client.chats.create( + account_id="accountID", + ) assert_matches_type(ChatCreateResponse, chat, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncBeeperDesktop) -> None: chat = await async_client.chats.create( - chat={ - "account_id": "accountID", - "participant_ids": ["string"], - "type": "single", - "message_text": "messageText", - "mode": "create", - "title": "title", + account_id="accountID", + allow_invite=True, + message_text="messageText", + mode="create", + participant_ids=["string"], + title="title", + type="single", + user={ + "id": "id", + "email": "email", + "full_name": "fullName", + "phone_number": "phoneNumber", + "username": "username", }, ) assert_matches_type(ChatCreateResponse, chat, path=["response"]) @parametrize async def test_raw_response_create(self, async_client: AsyncBeeperDesktop) -> None: - response = await async_client.chats.with_raw_response.create() + response = await async_client.chats.with_raw_response.create( + account_id="accountID", + ) assert response.is_closed is True assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -273,7 +295,9 @@ async def test_raw_response_create(self, async_client: AsyncBeeperDesktop) -> No @parametrize async def test_streaming_response_create(self, async_client: AsyncBeeperDesktop) -> None: - async with async_client.chats.with_streaming_response.create() as response: + async with async_client.chats.with_streaming_response.create( + account_id="accountID", + ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_messages.py b/tests/api_resources/test_messages.py index b6c3900..a167221 100644 --- a/tests/api_resources/test_messages.py +++ b/tests/api_resources/test_messages.py @@ -146,7 +146,7 @@ def test_method_search_with_all_params(self, client: BeeperDesktop) -> None: limit=20, media_types=["any"], query="dinner", - sender="me", + sender="sender", ) assert_matches_type(SyncCursorSearch[Message], message, path=["response"]) @@ -357,7 +357,7 @@ async def test_method_search_with_all_params(self, async_client: AsyncBeeperDesk limit=20, media_types=["any"], query="dinner", - sender="me", + sender="sender", ) assert_matches_type(AsyncCursorSearch[Message], message, path=["response"])