From f8133290552840e3723a0f67371a4481039c5ac6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 14:52:13 +0000 Subject: [PATCH 01/48] feat(api): api update --- .stats.yml | 4 ++-- src/Messages/MessageSearchParams.php | 14 ++++---------- src/Messages/MessageSearchParams/Sender.php | 15 --------------- src/ServiceContracts/MessagesContract.php | 5 ++--- src/Services/MessagesRawService.php | 3 +-- src/Services/MessagesService.php | 5 ++--- 6 files changed, 11 insertions(+), 35 deletions(-) delete mode 100644 src/Messages/MessageSearchParams/Sender.php diff --git a/.stats.yml b/.stats.yml index 8ec4701..5a6113f 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-774bb08472b6bb14c280fe5b767925675516b5c8ccc0b89b5abd7ac7bc30fe5a.yml -openapi_spec_hash: ddd1ce1f334b45206ac008b0f5296842 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper%2Fbeeper-desktop-api-4acef56b00be513f305543096fdd407e6947f0a5ad268ab2e627ff30b37a75db.yml +openapi_spec_hash: e876d796b6c25f18577f6be3944bf7d9 config_hash: b5ac0c1579dfe6257bcdb84cfd1002fc diff --git a/src/Messages/MessageSearchParams.php b/src/Messages/MessageSearchParams.php index e9ffe25..49d617f 100644 --- a/src/Messages/MessageSearchParams.php +++ b/src/Messages/MessageSearchParams.php @@ -11,7 +11,6 @@ use BeeperDesktop\Messages\MessageSearchParams\ChatType; use BeeperDesktop\Messages\MessageSearchParams\Direction; use BeeperDesktop\Messages\MessageSearchParams\MediaType; -use BeeperDesktop\Messages\MessageSearchParams\Sender; /** * Search messages across chats using Beeper's message index. @@ -31,7 +30,7 @@ * limit?: int|null, * mediaTypes?: list>|null, * query?: string|null, - * sender?: string|null|Sender|value-of, + * sender?: string|null, * } */ final class MessageSearchParams implements BaseModel @@ -124,10 +123,8 @@ final class MessageSearchParams implements BaseModel /** * Filter by sender: 'me' (messages sent by the authenticated user), 'others' (messages sent by others), or a specific user ID string (user.id). - * - * @var string|value-of|null $sender */ - #[Optional(enum: Sender::class)] + #[Optional] public ?string $sender; public function __construct() @@ -145,7 +142,6 @@ public function __construct() * @param ChatType|value-of|null $chatType * @param Direction|value-of|null $direction * @param list>|null $mediaTypes - * @param string|Sender|value-of|null $sender */ public static function with( ?array $accountIDs = null, @@ -160,7 +156,7 @@ public static function with( ?int $limit = null, ?array $mediaTypes = null, ?string $query = null, - Sender|string|null $sender = null, + ?string $sender = null, ): self { $self = new self; @@ -325,10 +321,8 @@ public function withQuery(string $query): self /** * Filter by sender: 'me' (messages sent by the authenticated user), 'others' (messages sent by others), or a specific user ID string (user.id). - * - * @param string|Sender|value-of $sender */ - public function withSender(Sender|string $sender): self + public function withSender(string $sender): self { $self = clone $this; $self['sender'] = $sender; diff --git a/src/Messages/MessageSearchParams/Sender.php b/src/Messages/MessageSearchParams/Sender.php deleted file mode 100644 index e58a8ab..0000000 --- a/src/Messages/MessageSearchParams/Sender.php +++ /dev/null @@ -1,15 +0,0 @@ -> $mediaTypes Filter messages by media types. Use ['any'] for any media type, or specify exact types like ['video', 'image']. Omit for no media filtering. * @param string $query Literal word search (non-semantic). Finds messages containing these EXACT words in any order. Use single words users actually type, not concepts or phrases. Example: use "dinner" not "dinner plans", use "sick" not "health issues". If omitted, returns results filtered only by other parameters. - * @param string|Sender|value-of $sender Filter by sender: 'me' (messages sent by the authenticated user), 'others' (messages sent by others), or a specific user ID string (user.id). + * @param string $sender Filter by sender: 'me' (messages sent by the authenticated user), 'others' (messages sent by others), or a specific user ID string (user.id). * @param RequestOpts|null $requestOptions * * @return CursorSearch @@ -94,7 +93,7 @@ public function search( int $limit = 20, ?array $mediaTypes = null, ?string $query = null, - Sender|string|null $sender = null, + ?string $sender = null, RequestOptions|array|null $requestOptions = null, ): CursorSearch; diff --git a/src/Services/MessagesRawService.php b/src/Services/MessagesRawService.php index 58ac32b..9d379ed 100644 --- a/src/Services/MessagesRawService.php +++ b/src/Services/MessagesRawService.php @@ -15,7 +15,6 @@ use BeeperDesktop\Messages\MessageSearchParams; use BeeperDesktop\Messages\MessageSearchParams\ChatType; use BeeperDesktop\Messages\MessageSearchParams\MediaType; -use BeeperDesktop\Messages\MessageSearchParams\Sender; use BeeperDesktop\Messages\MessageSendParams; use BeeperDesktop\Messages\MessageSendParams\Attachment; use BeeperDesktop\Messages\MessageSendResponse; @@ -127,7 +126,7 @@ public function list( * limit?: int, * mediaTypes?: list>, * query?: string, - * sender?: string|Sender|value-of, + * sender?: string, * }|MessageSearchParams $params * @param RequestOpts|null $requestOptions * diff --git a/src/Services/MessagesService.php b/src/Services/MessagesService.php index 70f0386..23d1d14 100644 --- a/src/Services/MessagesService.php +++ b/src/Services/MessagesService.php @@ -13,7 +13,6 @@ use BeeperDesktop\Messages\MessageListParams\Direction; use BeeperDesktop\Messages\MessageSearchParams\ChatType; use BeeperDesktop\Messages\MessageSearchParams\MediaType; -use BeeperDesktop\Messages\MessageSearchParams\Sender; use BeeperDesktop\Messages\MessageSendParams\Attachment; use BeeperDesktop\Messages\MessageSendResponse; use BeeperDesktop\Messages\MessageUpdateResponse; @@ -114,7 +113,7 @@ public function list( * @param int $limit maximum number of messages to return * @param list> $mediaTypes Filter messages by media types. Use ['any'] for any media type, or specify exact types like ['video', 'image']. Omit for no media filtering. * @param string $query Literal word search (non-semantic). Finds messages containing these EXACT words in any order. Use single words users actually type, not concepts or phrases. Example: use "dinner" not "dinner plans", use "sick" not "health issues". If omitted, returns results filtered only by other parameters. - * @param string|Sender|value-of $sender Filter by sender: 'me' (messages sent by the authenticated user), 'others' (messages sent by others), or a specific user ID string (user.id). + * @param string $sender Filter by sender: 'me' (messages sent by the authenticated user), 'others' (messages sent by others), or a specific user ID string (user.id). * @param RequestOpts|null $requestOptions * * @return CursorSearch @@ -134,7 +133,7 @@ public function search( int $limit = 20, ?array $mediaTypes = null, ?string $query = null, - Sender|string|null $sender = null, + ?string $sender = null, RequestOptions|array|null $requestOptions = null, ): CursorSearch { $params = Util::removeNulls( From fe6b606f1e40643b6f81a68bfbf467653d070a6a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 14:58:05 +0000 Subject: [PATCH 02/48] feat(api): api update --- .stats.yml | 2 +- src/Chats/ChatCreateParams.php | 191 ++++++++++++-- src/Chats/ChatCreateParams/Chat.php | 237 ------------------ .../ChatCreateParams/{Chat => }/Mode.php | 2 +- .../ChatCreateParams/{Chat => }/Type.php | 2 +- .../ChatCreateParams/{Chat => }/User.php | 2 +- src/ServiceContracts/ChatsContract.php | 36 ++- src/Services/ChatsRawService.php | 31 ++- src/Services/ChatsService.php | 49 +++- tests/Services/ChatsTest.php | 30 ++- 10 files changed, 280 insertions(+), 302 deletions(-) delete mode 100644 src/Chats/ChatCreateParams/Chat.php rename src/Chats/ChatCreateParams/{Chat => }/Mode.php (76%) rename src/Chats/ChatCreateParams/{Chat => }/Type.php (82%) rename src/Chats/ChatCreateParams/{Chat => }/User.php (98%) diff --git a/.stats.yml b/.stats.yml index 5a6113f..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-4acef56b00be513f305543096fdd407e6947f0a5ad268ab2e627ff30b37a75db.yml openapi_spec_hash: e876d796b6c25f18577f6be3944bf7d9 -config_hash: b5ac0c1579dfe6257bcdb84cfd1002fc +config_hash: 659111d4e28efa599b5f800619ed79c2 diff --git a/src/Chats/ChatCreateParams.php b/src/Chats/ChatCreateParams.php index 0bdb4bc..a476c25 100644 --- a/src/Chats/ChatCreateParams.php +++ b/src/Chats/ChatCreateParams.php @@ -4,7 +4,10 @@ namespace BeeperDesktop\Chats; -use BeeperDesktop\Chats\ChatCreateParams\Chat; +use BeeperDesktop\Chats\ChatCreateParams\Mode; +use BeeperDesktop\Chats\ChatCreateParams\Type; +use BeeperDesktop\Chats\ChatCreateParams\User; +use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Attributes\Required; use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Concerns\SdkParams; @@ -15,10 +18,17 @@ * * @see BeeperDesktop\Services\ChatsService::create() * - * @phpstan-import-type ChatShape from \BeeperDesktop\Chats\ChatCreateParams\Chat + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User * * @phpstan-type ChatCreateParamsShape = array{ - * chat: \BeeperDesktop\Chats\ChatCreateParams\Chat|ChatShape + * accountID: string, + * allowInvite?: bool|null, + * messageText?: string|null, + * mode?: null|Mode|value-of, + * participantIDs?: list|null, + * title?: string|null, + * type?: null|Type|value-of, + * user?: null|User|UserShape, * } */ final class ChatCreateParams implements BaseModel @@ -27,21 +37,72 @@ final class ChatCreateParams implements BaseModel use SdkModel; use SdkParams; + /** + * Account to create or start the chat on. + */ #[Required] - public Chat $chat; + public string $accountID; + + /** + * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. + */ + #[Optional] + public ?bool $allowInvite; + + /** + * Optional first message content if the platform requires it to create the chat. + */ + #[Optional] + public ?string $messageText; + + /** + * Operation mode. Defaults to 'create' when omitted. + * + * @var value-of|null $mode + */ + #[Optional(enum: Mode::class)] + public ?string $mode; + + /** + * Required when mode='create'. User IDs to include in the new chat. + * + * @var list|null $participantIDs + */ + #[Optional(list: 'string')] + public ?array $participantIDs; + + /** + * Optional title for group chats when mode='create'; ignored for single chats on most platforms. + */ + #[Optional] + public ?string $title; + + /** + * Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. + * + * @var value-of|null $type + */ + #[Optional(enum: Type::class)] + public ?string $type; + + /** + * Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. + */ + #[Optional] + public ?User $user; /** * `new ChatCreateParams()` is missing required properties by the API. * * To enforce required parameters use * ``` - * ChatCreateParams::with(chat: ...) + * ChatCreateParams::with(accountID: ...) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new ChatCreateParams)->withChat(...) + * (new ChatCreateParams)->withAccountID(...) * ``` */ public function __construct() @@ -54,26 +115,128 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param Chat|ChatShape $chat + * @param Mode|value-of|null $mode + * @param list|null $participantIDs + * @param Type|value-of|null $type + * @param User|UserShape|null $user */ public static function with( - Chat|array $chat + string $accountID, + ?bool $allowInvite = null, + ?string $messageText = null, + Mode|string|null $mode = null, + ?array $participantIDs = null, + ?string $title = null, + Type|string|null $type = null, + User|array|null $user = null, ): self { $self = new self; - $self['chat'] = $chat; + $self['accountID'] = $accountID; + + null !== $allowInvite && $self['allowInvite'] = $allowInvite; + null !== $messageText && $self['messageText'] = $messageText; + null !== $mode && $self['mode'] = $mode; + null !== $participantIDs && $self['participantIDs'] = $participantIDs; + null !== $title && $self['title'] = $title; + null !== $type && $self['type'] = $type; + null !== $user && $self['user'] = $user; return $self; } /** - * @param Chat|ChatShape $chat + * Account to create or start the chat on. */ - public function withChat( - Chat|array $chat - ): self { + public function withAccountID(string $accountID): self + { + $self = clone $this; + $self['accountID'] = $accountID; + + return $self; + } + + /** + * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. + */ + public function withAllowInvite(bool $allowInvite): self + { + $self = clone $this; + $self['allowInvite'] = $allowInvite; + + return $self; + } + + /** + * Optional first message content if the platform requires it to create the chat. + */ + public function withMessageText(string $messageText): self + { + $self = clone $this; + $self['messageText'] = $messageText; + + return $self; + } + + /** + * Operation mode. Defaults to 'create' when omitted. + * + * @param Mode|value-of $mode + */ + public function withMode(Mode|string $mode): self + { + $self = clone $this; + $self['mode'] = $mode; + + return $self; + } + + /** + * Required when mode='create'. User IDs to include in the new chat. + * + * @param list $participantIDs + */ + public function withParticipantIDs(array $participantIDs): self + { + $self = clone $this; + $self['participantIDs'] = $participantIDs; + + return $self; + } + + /** + * Optional title for group chats when mode='create'; ignored for single chats on most platforms. + */ + public function withTitle(string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } + + /** + * Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. + * + * @param User|UserShape $user + */ + public function withUser(User|array $user): self + { $self = clone $this; - $self['chat'] = $chat; + $self['user'] = $user; return $self; } diff --git a/src/Chats/ChatCreateParams/Chat.php b/src/Chats/ChatCreateParams/Chat.php deleted file mode 100644 index d1d63c2..0000000 --- a/src/Chats/ChatCreateParams/Chat.php +++ /dev/null @@ -1,237 +0,0 @@ -, - * participantIDs?: list|null, - * title?: string|null, - * type?: null|Type|value-of, - * user?: null|User|UserShape, - * } - */ -final class Chat implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - - /** - * Account to create or start the chat on. - */ - #[Required] - public string $accountID; - - /** - * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. - */ - #[Optional] - public ?bool $allowInvite; - - /** - * Optional first message content if the platform requires it to create the chat. - */ - #[Optional] - public ?string $messageText; - - /** - * Operation mode. Defaults to 'create' when omitted. - * - * @var value-of|null $mode - */ - #[Optional(enum: Mode::class)] - public ?string $mode; - - /** - * Required when mode='create'. User IDs to include in the new chat. - * - * @var list|null $participantIDs - */ - #[Optional(list: 'string')] - public ?array $participantIDs; - - /** - * Optional title for group chats when mode='create'; ignored for single chats on most platforms. - */ - #[Optional] - public ?string $title; - - /** - * Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. - * - * @var value-of|null $type - */ - #[Optional(enum: Type::class)] - public ?string $type; - - /** - * Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. - */ - #[Optional] - public ?User $user; - - /** - * `new Chat()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * Chat::with(accountID: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new Chat)->withAccountID(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param Mode|value-of|null $mode - * @param list|null $participantIDs - * @param Type|value-of|null $type - * @param User|UserShape|null $user - */ - public static function with( - string $accountID, - ?bool $allowInvite = null, - ?string $messageText = null, - Mode|string|null $mode = null, - ?array $participantIDs = null, - ?string $title = null, - Type|string|null $type = null, - User|array|null $user = null, - ): self { - $self = new self; - - $self['accountID'] = $accountID; - - null !== $allowInvite && $self['allowInvite'] = $allowInvite; - null !== $messageText && $self['messageText'] = $messageText; - null !== $mode && $self['mode'] = $mode; - null !== $participantIDs && $self['participantIDs'] = $participantIDs; - null !== $title && $self['title'] = $title; - null !== $type && $self['type'] = $type; - null !== $user && $self['user'] = $user; - - return $self; - } - - /** - * Account to create or start the chat on. - */ - public function withAccountID(string $accountID): self - { - $self = clone $this; - $self['accountID'] = $accountID; - - return $self; - } - - /** - * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. - */ - public function withAllowInvite(bool $allowInvite): self - { - $self = clone $this; - $self['allowInvite'] = $allowInvite; - - return $self; - } - - /** - * Optional first message content if the platform requires it to create the chat. - */ - public function withMessageText(string $messageText): self - { - $self = clone $this; - $self['messageText'] = $messageText; - - return $self; - } - - /** - * Operation mode. Defaults to 'create' when omitted. - * - * @param Mode|value-of $mode - */ - public function withMode(Mode|string $mode): self - { - $self = clone $this; - $self['mode'] = $mode; - - return $self; - } - - /** - * Required when mode='create'. User IDs to include in the new chat. - * - * @param list $participantIDs - */ - public function withParticipantIDs(array $participantIDs): self - { - $self = clone $this; - $self['participantIDs'] = $participantIDs; - - return $self; - } - - /** - * Optional title for group chats when mode='create'; ignored for single chats on most platforms. - */ - public function withTitle(string $title): self - { - $self = clone $this; - $self['title'] = $title; - - return $self; - } - - /** - * Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. - * - * @param Type|value-of $type - */ - public function withType(Type|string $type): self - { - $self = clone $this; - $self['type'] = $type; - - return $self; - } - - /** - * Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. - * - * @param User|UserShape $user - */ - public function withUser(User|array $user): self - { - $self = clone $this; - $self['user'] = $user; - - return $self; - } -} diff --git a/src/Chats/ChatCreateParams/Chat/Mode.php b/src/Chats/ChatCreateParams/Mode.php similarity index 76% rename from src/Chats/ChatCreateParams/Chat/Mode.php rename to src/Chats/ChatCreateParams/Mode.php index ce0dabd..8ade752 100644 --- a/src/Chats/ChatCreateParams/Chat/Mode.php +++ b/src/Chats/ChatCreateParams/Mode.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace BeeperDesktop\Chats\ChatCreateParams\Chat; +namespace BeeperDesktop\Chats\ChatCreateParams; /** * Operation mode. Defaults to 'create' when omitted. diff --git a/src/Chats/ChatCreateParams/Chat/Type.php b/src/Chats/ChatCreateParams/Type.php similarity index 82% rename from src/Chats/ChatCreateParams/Chat/Type.php rename to src/Chats/ChatCreateParams/Type.php index 630c2f6..16d7400 100644 --- a/src/Chats/ChatCreateParams/Chat/Type.php +++ b/src/Chats/ChatCreateParams/Type.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace BeeperDesktop\Chats\ChatCreateParams\Chat; +namespace BeeperDesktop\Chats\ChatCreateParams; /** * Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. diff --git a/src/Chats/ChatCreateParams/Chat/User.php b/src/Chats/ChatCreateParams/User.php similarity index 98% rename from src/Chats/ChatCreateParams/Chat/User.php rename to src/Chats/ChatCreateParams/User.php index df629a7..3f60298 100644 --- a/src/Chats/ChatCreateParams/Chat/User.php +++ b/src/Chats/ChatCreateParams/User.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace BeeperDesktop\Chats\ChatCreateParams\Chat; +namespace BeeperDesktop\Chats\ChatCreateParams; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Concerns\SdkModel; diff --git a/src/ServiceContracts/ChatsContract.php b/src/ServiceContracts/ChatsContract.php index e86488b..1c30811 100644 --- a/src/ServiceContracts/ChatsContract.php +++ b/src/ServiceContracts/ChatsContract.php @@ -4,20 +4,22 @@ namespace BeeperDesktop\ServiceContracts; -use BeeperDesktop\Chats\ChatCreateParams\Chat; +use BeeperDesktop\Chats\Chat; +use BeeperDesktop\Chats\ChatCreateParams\Mode; +use BeeperDesktop\Chats\ChatCreateParams\Type; +use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; use BeeperDesktop\Chats\ChatNewResponse; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; -use BeeperDesktop\Chats\ChatSearchParams\Type; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; use BeeperDesktop\RequestOptions; /** - * @phpstan-import-type ChatShape from \BeeperDesktop\Chats\ChatCreateParams\Chat + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ interface ChatsContract @@ -25,14 +27,28 @@ interface ChatsContract /** * @api * - * @param Chat|ChatShape $chat + * @param string $accountID account to create or start the chat on + * @param bool $allowInvite Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. + * @param string $messageText optional first message content if the platform requires it to create the chat + * @param Mode|value-of $mode Operation mode. Defaults to 'create' when omitted. + * @param list $participantIDs Required when mode='create'. User IDs to include in the new chat. + * @param string $title optional title for group chats when mode='create'; ignored for single chats on most platforms + * @param Type|value-of $type Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. + * @param User|UserShape $user Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. * @param RequestOpts|null $requestOptions * * @throws APIException */ public function create( - Chat|array $chat, - RequestOptions|array|null $requestOptions = null + string $accountID, + bool $allowInvite = true, + ?string $messageText = null, + Mode|string|null $mode = null, + ?array $participantIDs = null, + ?string $title = null, + Type|string|null $type = null, + User|array|null $user = null, + RequestOptions|array|null $requestOptions = null, ): ChatNewResponse; /** @@ -48,7 +64,7 @@ public function retrieve( string $chatID, ?int $maxParticipantCount = -1, RequestOptions|array|null $requestOptions = null, - ): \BeeperDesktop\Chats\Chat; + ): Chat; /** * @api @@ -97,11 +113,11 @@ public function archive( * @param int $limit Set the maximum number of chats to retrieve. Valid range: 1-200, default is 50 * @param string $query Literal token search (non-semantic). Use single words users type (e.g., "dinner"). When multiple words provided, ALL must match. Case-insensitive. * @param Scope|value-of $scope search scope: 'titles' matches title + network; 'participants' matches participant names - * @param Type|value-of $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types + * @param \BeeperDesktop\Chats\ChatSearchParams\Type|value-of<\BeeperDesktop\Chats\ChatSearchParams\Type> $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types * @param bool|null $unreadOnly Set to true to only retrieve chats that have unread messages * @param RequestOpts|null $requestOptions * - * @return CursorSearch<\BeeperDesktop\Chats\Chat> + * @return CursorSearch * * @throws APIException */ @@ -116,7 +132,7 @@ public function search( int $limit = 50, ?string $query = null, Scope|string $scope = 'titles', - Type|string $type = 'any', + \BeeperDesktop\Chats\ChatSearchParams\Type|string $type = 'any', ?bool $unreadOnly = null, RequestOptions|array|null $requestOptions = null, ): CursorSearch; diff --git a/src/Services/ChatsRawService.php b/src/Services/ChatsRawService.php index 1df2645..d54d92b 100644 --- a/src/Services/ChatsRawService.php +++ b/src/Services/ChatsRawService.php @@ -4,9 +4,12 @@ namespace BeeperDesktop\Services; +use BeeperDesktop\Chats\Chat; use BeeperDesktop\Chats\ChatArchiveParams; use BeeperDesktop\Chats\ChatCreateParams; -use BeeperDesktop\Chats\ChatCreateParams\Chat; +use BeeperDesktop\Chats\ChatCreateParams\Mode; +use BeeperDesktop\Chats\ChatCreateParams\Type; +use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Chats\ChatListParams; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; @@ -15,7 +18,6 @@ use BeeperDesktop\Chats\ChatSearchParams; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; -use BeeperDesktop\Chats\ChatSearchParams\Type; use BeeperDesktop\Client; use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; @@ -27,7 +29,7 @@ /** * Manage chats. * - * @phpstan-import-type ChatShape from \BeeperDesktop\Chats\ChatCreateParams\Chat + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class ChatsRawService implements ChatsRawContract @@ -43,7 +45,16 @@ public function __construct(private Client $client) {} * * Create a single/group chat (mode='create') or start a direct chat from merged user data (mode='start'). * - * @param array{chat: Chat|ChatShape}|ChatCreateParams $params + * @param array{ + * accountID: string, + * allowInvite?: bool, + * messageText?: string, + * mode?: Mode|value-of, + * participantIDs?: list, + * title?: string, + * type?: Type|value-of, + * user?: User|UserShape, + * }|ChatCreateParams $params * @param RequestOpts|null $requestOptions * * @return BaseResponse @@ -63,7 +74,7 @@ public function create( return $this->client->request( method: 'post', path: 'v1/chats', - body: (object) $parsed['chat'], + body: (object) $parsed, options: $options, convert: ChatNewResponse::class, ); @@ -78,7 +89,7 @@ public function create( * @param array{maxParticipantCount?: int|null}|ChatRetrieveParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse<\BeeperDesktop\Chats\Chat> + * @return BaseResponse * * @throws APIException */ @@ -98,7 +109,7 @@ public function retrieve( path: ['v1/chats/%1$s', $chatID], query: $parsed, options: $options, - convert: \BeeperDesktop\Chats\Chat::class, + convert: Chat::class, ); } @@ -187,12 +198,12 @@ public function archive( * limit?: int, * query?: string, * scope?: Scope|value-of, - * type?: Type|value-of, + * type?: ChatSearchParams\Type|value-of, * unreadOnly?: bool|null, * }|ChatSearchParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse> + * @return BaseResponse> * * @throws APIException */ @@ -211,7 +222,7 @@ public function search( path: 'v1/chats/search', query: $parsed, options: $options, - convert: \BeeperDesktop\Chats\Chat::class, + convert: Chat::class, page: CursorSearch::class, ); } diff --git a/src/Services/ChatsService.php b/src/Services/ChatsService.php index 8ca0439..fbeb607 100644 --- a/src/Services/ChatsService.php +++ b/src/Services/ChatsService.php @@ -4,13 +4,15 @@ namespace BeeperDesktop\Services; -use BeeperDesktop\Chats\ChatCreateParams\Chat; +use BeeperDesktop\Chats\Chat; +use BeeperDesktop\Chats\ChatCreateParams\Mode; +use BeeperDesktop\Chats\ChatCreateParams\Type; +use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; use BeeperDesktop\Chats\ChatNewResponse; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; -use BeeperDesktop\Chats\ChatSearchParams\Type; use BeeperDesktop\Client; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\Core\Util; @@ -24,7 +26,7 @@ /** * Manage chats. * - * @phpstan-import-type ChatShape from \BeeperDesktop\Chats\ChatCreateParams\Chat + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class ChatsService implements ChatsContract @@ -59,16 +61,41 @@ public function __construct(private Client $client) * * Create a single/group chat (mode='create') or start a direct chat from merged user data (mode='start'). * - * @param Chat|ChatShape $chat + * @param string $accountID account to create or start the chat on + * @param bool $allowInvite Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. + * @param string $messageText optional first message content if the platform requires it to create the chat + * @param Mode|value-of $mode Operation mode. Defaults to 'create' when omitted. + * @param list $participantIDs Required when mode='create'. User IDs to include in the new chat. + * @param string $title optional title for group chats when mode='create'; ignored for single chats on most platforms + * @param Type|value-of $type Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. + * @param User|UserShape $user Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. * @param RequestOpts|null $requestOptions * * @throws APIException */ public function create( - Chat|array $chat, - RequestOptions|array|null $requestOptions = null + string $accountID, + bool $allowInvite = true, + ?string $messageText = null, + Mode|string|null $mode = null, + ?array $participantIDs = null, + ?string $title = null, + Type|string|null $type = null, + User|array|null $user = null, + RequestOptions|array|null $requestOptions = null, ): ChatNewResponse { - $params = Util::removeNulls(['chat' => $chat]); + $params = Util::removeNulls( + [ + 'accountID' => $accountID, + 'allowInvite' => $allowInvite, + 'messageText' => $messageText, + 'mode' => $mode, + 'participantIDs' => $participantIDs, + 'title' => $title, + 'type' => $type, + 'user' => $user, + ], + ); // @phpstan-ignore-next-line argument.type $response = $this->raw->create(params: $params, requestOptions: $requestOptions); @@ -91,7 +118,7 @@ public function retrieve( string $chatID, ?int $maxParticipantCount = -1, RequestOptions|array|null $requestOptions = null, - ): \BeeperDesktop\Chats\Chat { + ): Chat { $params = Util::removeNulls( ['maxParticipantCount' => $maxParticipantCount] ); @@ -175,11 +202,11 @@ public function archive( * @param int $limit Set the maximum number of chats to retrieve. Valid range: 1-200, default is 50 * @param string $query Literal token search (non-semantic). Use single words users type (e.g., "dinner"). When multiple words provided, ALL must match. Case-insensitive. * @param Scope|value-of $scope search scope: 'titles' matches title + network; 'participants' matches participant names - * @param Type|value-of $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types + * @param \BeeperDesktop\Chats\ChatSearchParams\Type|value-of<\BeeperDesktop\Chats\ChatSearchParams\Type> $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types * @param bool|null $unreadOnly Set to true to only retrieve chats that have unread messages * @param RequestOpts|null $requestOptions * - * @return CursorSearch<\BeeperDesktop\Chats\Chat> + * @return CursorSearch * * @throws APIException */ @@ -194,7 +221,7 @@ public function search( int $limit = 50, ?string $query = null, Scope|string $scope = 'titles', - Type|string $type = 'any', + \BeeperDesktop\Chats\ChatSearchParams\Type|string $type = 'any', ?bool $unreadOnly = null, RequestOptions|array|null $requestOptions = null, ): CursorSearch { diff --git a/tests/Services/ChatsTest.php b/tests/Services/ChatsTest.php index 71d8111..6678d05 100644 --- a/tests/Services/ChatsTest.php +++ b/tests/Services/ChatsTest.php @@ -34,7 +34,7 @@ protected function setUp(): void #[Test] public function testCreate(): void { - $result = $this->client->chats->create(chat: ['accountID' => 'accountID']); + $result = $this->client->chats->create(accountID: 'accountID'); // @phpstan-ignore-next-line method.alreadyNarrowedType $this->assertInstanceOf(ChatNewResponse::class, $result); @@ -44,21 +44,19 @@ public function testCreate(): void public function testCreateWithOptionalParams(): void { $result = $this->client->chats->create( - chat: [ - 'accountID' => 'accountID', - 'allowInvite' => true, - 'messageText' => 'messageText', - 'mode' => 'create', - 'participantIDs' => ['string'], - 'title' => 'title', - 'type' => 'single', - 'user' => [ - 'id' => 'id', - 'email' => 'email', - 'fullName' => 'fullName', - 'phoneNumber' => 'phoneNumber', - 'username' => 'username', - ], + accountID: 'accountID', + allowInvite: true, + messageText: 'messageText', + mode: 'create', + participantIDs: ['string'], + title: 'title', + type: 'single', + user: [ + 'id' => 'id', + 'email' => 'email', + 'fullName' => 'fullName', + 'phoneNumber' => 'phoneNumber', + 'username' => 'username', ], ); From b33be1bf3f1180bbf784d670d06e7bbef46c7253 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:38:25 +0000 Subject: [PATCH 03/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 56c368e..eea9217 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-4acef56b00be513f305543096fdd407e6947f0a5ad268ab2e627ff30b37a75db.yml openapi_spec_hash: e876d796b6c25f18577f6be3944bf7d9 -config_hash: 659111d4e28efa599b5f800619ed79c2 +config_hash: 66617ffb2c7b6ef016e9704e766e7f65 From e0986159d91fbd76d8647de9e2f7e2f1aedb071f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:39:31 +0000 Subject: [PATCH 04/48] feat(api): api update --- .stats.yml | 6 +++--- README.md | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.stats.yml b/.stats.yml index eea9217..6e96390 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-4acef56b00be513f305543096fdd407e6947f0a5ad268ab2e627ff30b37a75db.yml -openapi_spec_hash: e876d796b6c25f18577f6be3944bf7d9 -config_hash: 66617ffb2c7b6ef016e9704e766e7f65 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper%2Fbeeper-desktop-api-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml +openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a +config_hash: 659111d4e28efa599b5f800619ed79c2 diff --git a/README.md b/README.md index b5d91b8..e4e22ab 100644 --- a/README.md +++ b/README.md @@ -38,9 +38,7 @@ Parameters with a default value must be set by name. use BeeperDesktop\Client; -$client = new Client( - accessToken: getenv('BEEPER_ACCESS_TOKEN') ?: 'My Access Token' -); +$client = new Client(); $page = $client->chats->search(includeMuted: true, limit: 3, type: 'single'); @@ -65,9 +63,7 @@ This library provides auto-paginating iterators with each list response, so you use BeeperDesktop\Client; -$client = new Client( - accessToken: getenv('BEEPER_ACCESS_TOKEN') ?: 'My Access Token' -); +$client = new Client(); $page = $client->messages->search( accountIDs: ['local-telegram_ba_QFrb5lrLPhO3OT5MFBeTWv0x4BI'], From 239a1d8d35c70083b474adf0f1bd497164cc9011 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:41:54 +0000 Subject: [PATCH 05/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 6e96390..ea5e4be 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: 659111d4e28efa599b5f800619ed79c2 +config_hash: 66617ffb2c7b6ef016e9704e766e7f65 From 987a67abe0d4f574ba9839a670d7cfb273040698 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:58:29 +0000 Subject: [PATCH 06/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index ea5e4be..7c03a30 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: 66617ffb2c7b6ef016e9704e766e7f65 +config_hash: 2f5c2448fc8eec47bb412de39beb09dc From 6789612a1bf78af5afa4123ee8ea0223acc71261 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:59:30 +0000 Subject: [PATCH 07/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 7c03a30..004aab8 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: 2f5c2448fc8eec47bb412de39beb09dc +config_hash: aa49273410d42fb96c5515dbce1f182f From 958db5719fcca4f33c8b9c4796e34b8a3c5a8d91 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Feb 2026 05:54:54 +0000 Subject: [PATCH 08/48] chore(internal): upgrade phpunit --- composer.lock | 120 +++++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 54 deletions(-) diff --git a/composer.lock b/composer.lock index 3f6c209..7a5e63d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5fc63f7c84d94b42416689723c547f69", + "content-hash": "ffa287ea8babf60e021f37e62c6c207a", "packages": [ { "name": "php-http/discovery", @@ -194,16 +194,16 @@ "packages-dev": [ { "name": "brianium/paratest", - "version": "v7.8.4", + "version": "v7.8.5", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "130a9bf0e269ee5f5b320108f794ad03e275cad4" + "reference": "9b324c8fc319cf9728b581c7a90e1c8f6361c5e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/130a9bf0e269ee5f5b320108f794ad03e275cad4", - "reference": "130a9bf0e269ee5f5b320108f794ad03e275cad4", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/9b324c8fc319cf9728b581c7a90e1c8f6361c5e5", + "reference": "9b324c8fc319cf9728b581c7a90e1c8f6361c5e5", "shasum": "" }, "require": { @@ -211,27 +211,27 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-simplexml": "*", - "fidry/cpu-core-counter": "^1.2.0", + "fidry/cpu-core-counter": "^1.3.0", "jean85/pretty-package-versions": "^2.1.1", - "php": "~8.2.0 || ~8.3.0 || ~8.4.0", - "phpunit/php-code-coverage": "^11.0.10", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "phpunit/php-code-coverage": "^11.0.12", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-timer": "^7.0.1", - "phpunit/phpunit": "^11.5.24", + "phpunit/phpunit": "^11.5.46", "sebastian/environment": "^7.2.1", - "symfony/console": "^6.4.22 || ^7.3.0", - "symfony/process": "^6.4.20 || ^7.3.0" + "symfony/console": "^6.4.22 || ^7.3.4 || ^8.0.3", + "symfony/process": "^6.4.20 || ^7.3.4 || ^8.0.3" }, "require-dev": { "doctrine/coding-standard": "^12.0.0", "ext-pcov": "*", "ext-posix": "*", - "phpstan/phpstan": "^2.1.17", + "phpstan/phpstan": "^2.1.33", "phpstan/phpstan-deprecation-rules": "^2.0.3", - "phpstan/phpstan-phpunit": "^2.0.6", - "phpstan/phpstan-strict-rules": "^2.0.4", - "squizlabs/php_codesniffer": "^3.13.2", - "symfony/filesystem": "^6.4.13 || ^7.3.0" + "phpstan/phpstan-phpunit": "^2.0.11", + "phpstan/phpstan-strict-rules": "^2.0.7", + "squizlabs/php_codesniffer": "^3.13.5", + "symfony/filesystem": "^6.4.13 || ^7.3.2 || ^8.0.1" }, "bin": [ "bin/paratest", @@ -271,7 +271,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.8.4" + "source": "https://github.com/paratestphp/paratest/tree/v7.8.5" }, "funding": [ { @@ -283,7 +283,7 @@ "type": "paypal" } ], - "time": "2025-06-23T06:07:21+00:00" + "time": "2026-01-08T08:02:38+00:00" }, { "name": "clue/ndjson-react", @@ -1412,38 +1412,38 @@ }, { "name": "pestphp/pest", - "version": "v3.8.4", + "version": "v3.8.5", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "72cf695554420e21858cda831d5db193db102574" + "reference": "7796630eafcfd1c02660cecdde3bc6984fbf01f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/72cf695554420e21858cda831d5db193db102574", - "reference": "72cf695554420e21858cda831d5db193db102574", + "url": "https://api.github.com/repos/pestphp/pest/zipball/7796630eafcfd1c02660cecdde3bc6984fbf01f4", + "reference": "7796630eafcfd1c02660cecdde3bc6984fbf01f4", "shasum": "" }, "require": { - "brianium/paratest": "^7.8.4", - "nunomaduro/collision": "^8.8.2", - "nunomaduro/termwind": "^2.3.1", + "brianium/paratest": "^7.8.5", + "nunomaduro/collision": "^8.8.3", + "nunomaduro/termwind": "^2.3.3", "pestphp/pest-plugin": "^3.0.0", "pestphp/pest-plugin-arch": "^3.1.1", "pestphp/pest-plugin-mutate": "^3.0.5", "php": "^8.2.0", - "phpunit/phpunit": "^11.5.33" + "phpunit/phpunit": "^11.5.50" }, "conflict": { "filp/whoops": "<2.16.0", - "phpunit/phpunit": ">11.5.33", + "phpunit/phpunit": ">11.5.50", "sebastian/exporter": "<6.0.0", "webmozart/assert": "<1.11.0" }, "require-dev": { "pestphp/pest-dev-tools": "^3.4.0", "pestphp/pest-plugin-type-coverage": "^3.6.1", - "symfony/process": "^7.3.0" + "symfony/process": "^7.4.4" }, "bin": [ "bin/pest" @@ -1508,7 +1508,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v3.8.4" + "source": "https://github.com/pestphp/pest/tree/v3.8.5" }, "funding": [ { @@ -1520,7 +1520,7 @@ "type": "github" } ], - "time": "2025-08-20T19:12:42+00:00" + "time": "2026-01-28T01:33:45+00:00" }, { "name": "pestphp/pest-plugin", @@ -2627,28 +2627,28 @@ }, { "name": "phpunit/php-file-iterator", - "version": "5.1.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", - "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/2f3a64888c814fc235386b7387dd5b5ed92ad903", + "reference": "2f3a64888c814fc235386b7387dd5b5ed92ad903", "shasum": "" }, "require": { "php": ">=8.2" }, "require-dev": { - "phpunit/phpunit": "^11.0" + "phpunit/phpunit": "^11.3" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -2676,15 +2676,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.1" }, "funding": [ { "url": "https://github.com/sebastianbergmann", "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator", + "type": "tidelift" } ], - "time": "2024-08-27T05:02:59+00:00" + "time": "2026-02-02T13:52:54+00:00" }, { "name": "phpunit/php-invoker", @@ -2872,16 +2884,16 @@ }, { "name": "phpunit/phpunit", - "version": "11.5.33", + "version": "11.5.50", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "5965e9ff57546cb9137c0ff6aa78cb7442b05cf6" + "reference": "fdfc727f0fcacfeb8fcb30c7e5da173125b58be3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5965e9ff57546cb9137c0ff6aa78cb7442b05cf6", - "reference": "5965e9ff57546cb9137c0ff6aa78cb7442b05cf6", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fdfc727f0fcacfeb8fcb30c7e5da173125b58be3", + "reference": "fdfc727f0fcacfeb8fcb30c7e5da173125b58be3", "shasum": "" }, "require": { @@ -2895,17 +2907,17 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.2", - "phpunit/php-code-coverage": "^11.0.10", + "phpunit/php-code-coverage": "^11.0.12", "phpunit/php-file-iterator": "^5.1.0", "phpunit/php-invoker": "^5.0.1", "phpunit/php-text-template": "^4.0.1", "phpunit/php-timer": "^7.0.1", "sebastian/cli-parser": "^3.0.2", "sebastian/code-unit": "^3.0.3", - "sebastian/comparator": "^6.3.2", + "sebastian/comparator": "^6.3.3", "sebastian/diff": "^6.0.2", "sebastian/environment": "^7.2.1", - "sebastian/exporter": "^6.3.0", + "sebastian/exporter": "^6.3.2", "sebastian/global-state": "^7.0.2", "sebastian/object-enumerator": "^6.0.1", "sebastian/type": "^5.1.3", @@ -2953,7 +2965,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.33" + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.50" }, "funding": [ { @@ -2977,7 +2989,7 @@ "type": "tidelift" } ], - "time": "2025-08-16T05:19:02+00:00" + "time": "2026-01-27T05:59:18+00:00" }, { "name": "psr/container", @@ -3936,16 +3948,16 @@ }, { "name": "sebastian/comparator", - "version": "6.3.2", + "version": "6.3.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8" + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8", - "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", + "reference": "2c95e1e86cb8dd41beb8d502057d1081ccc8eca9", "shasum": "" }, "require": { @@ -4004,7 +4016,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2" + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.3" }, "funding": [ { @@ -4024,7 +4036,7 @@ "type": "tidelift" } ], - "time": "2025-08-10T08:07:46+00:00" + "time": "2026-01-24T09:26:40+00:00" }, { "name": "sebastian/complexity", @@ -6668,5 +6680,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } From 297da598fb4ba18fec57a63e461e4316f3d6e641 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2026 05:47:54 +0000 Subject: [PATCH 09/48] chore(internal): codegen related update --- src/Core/Conversion.php | 31 +++++++++++++++++++ .../BeeperDesktopClientRawService.php | 2 ++ src/Services/BeeperDesktopClientService.php | 2 ++ src/Services/InfoRawService.php | 2 ++ src/Services/InfoService.php | 2 ++ 5 files changed, 39 insertions(+) diff --git a/src/Core/Conversion.php b/src/Core/Conversion.php index 494ec69..b903d2f 100644 --- a/src/Core/Conversion.php +++ b/src/Core/Conversion.php @@ -170,6 +170,37 @@ private static function tryConvert(Converter|ConverterSource|string $target, mix return $value; + case 'DateTimeInterface': + case 'DateTimeImmutable': + if (is_string($value)) { + try { + ++$state->maybe; + + return new \DateTimeImmutable($value); + } catch (\Exception) { + --$state->maybe; + } + } + + ++$state->no; + + return $value; + + case 'DateTime': + if (is_string($value)) { + try { + ++$state->maybe; + + return new \DateTime($value); + } catch (\Exception) { + --$state->maybe; + } + } + + ++$state->no; + + return $value; + default: ++$state->no; diff --git a/src/Services/BeeperDesktopClientRawService.php b/src/Services/BeeperDesktopClientRawService.php index e40a60d..ee0acfe 100644 --- a/src/Services/BeeperDesktopClientRawService.php +++ b/src/Services/BeeperDesktopClientRawService.php @@ -15,6 +15,8 @@ use BeeperDesktop\ServiceContracts\BeeperDesktopClientRawContract; /** + * Control the Beeper Desktop application. + * * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class BeeperDesktopClientRawService implements BeeperDesktopClientRawContract diff --git a/src/Services/BeeperDesktopClientService.php b/src/Services/BeeperDesktopClientService.php index 9f2272f..0d44a9a 100644 --- a/src/Services/BeeperDesktopClientService.php +++ b/src/Services/BeeperDesktopClientService.php @@ -13,6 +13,8 @@ use BeeperDesktop\ServiceContracts\BeeperDesktopClientContract; /** + * Control the Beeper Desktop application. + * * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class BeeperDesktopClientService implements BeeperDesktopClientContract diff --git a/src/Services/InfoRawService.php b/src/Services/InfoRawService.php index 853a5b8..9ed5030 100644 --- a/src/Services/InfoRawService.php +++ b/src/Services/InfoRawService.php @@ -12,6 +12,8 @@ use BeeperDesktop\ServiceContracts\InfoRawContract; /** + * Control the Beeper Desktop application. + * * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class InfoRawService implements InfoRawContract diff --git a/src/Services/InfoService.php b/src/Services/InfoService.php index c38342e..20ccaf2 100644 --- a/src/Services/InfoService.php +++ b/src/Services/InfoService.php @@ -11,6 +11,8 @@ use BeeperDesktop\ServiceContracts\InfoContract; /** + * Control the Beeper Desktop application. + * * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class InfoService implements InfoContract From 344cf76b4dc4c254d6c380f035e8b6d2d86fb138 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 5 Mar 2026 22:00:51 +0000 Subject: [PATCH 10/48] chore(test): do not count install time for mock server timeout --- scripts/mock | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/mock b/scripts/mock index 0b28f6e..bcf3b39 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,11 +21,22 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then + # Pre-install the package so the download doesn't eat into the startup timeout + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & - # Wait for server to come online + # Wait for server to come online (max 30s) echo -n "Waiting for server" + attempts=0 while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + attempts=$((attempts + 1)) + if [ "$attempts" -ge 300 ]; then + echo + echo "Timed out waiting for Prism server to start" + cat .prism.log + exit 1 + fi echo -n "." sleep 0.1 done From a26c7a0c2f2aa969a455725611e427be96fddefa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 01:45:27 +0000 Subject: [PATCH 11/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 004aab8..06ba3c3 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: aa49273410d42fb96c5515dbce1f182f +config_hash: bfb432c69dc0a8d273043a3cdd87ffe1 From fa1363196602d79f987910512999798700539386 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 01:46:37 +0000 Subject: [PATCH 12/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 06ba3c3..72a5288 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: bfb432c69dc0a8d273043a3cdd87ffe1 +config_hash: a7eb18d34cd75f7dbffe1940df6b2e9e From 46dbc095defeac9aa95e41cd668e883fcd20bea9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 17:21:57 +0000 Subject: [PATCH 13/48] feat(api): manual updates --- .stats.yml | 2 +- README.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 72a5288..5dbc3d6 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: a7eb18d34cd75f7dbffe1940df6b2e9e +config_hash: 6fc4359a793fc3fc9ac01712b5ef8c0d diff --git a/README.md b/README.md index e4e22ab..a027b75 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ The Beeper Desktop PHP library provides convenient access to the Beeper Desktop REST API from any PHP 8.1.0+ application. +It is generated with [Stainless](https://www.stainless.com/). + ## Documentation The REST API documentation can be found on [developers.beeper.com](https://developers.beeper.com/desktop-api/). From dd063fd26956c4b4962b94570e4168d0e1d21ceb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 14:36:09 +0000 Subject: [PATCH 14/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 5dbc3d6..2b39be6 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: 6fc4359a793fc3fc9ac01712b5ef8c0d +config_hash: ca148af6be59ec54295b2c5f852a38d1 From d3967d0433e63e905f0d9699da709a7544ec12db Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 03:38:20 +0000 Subject: [PATCH 15/48] chore(internal): tweak CI branches --- .github/workflows/ci.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2509fdf..71a6437 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' From b2a099467ced88b63d36ae05aa4db7da5b5c64c8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 02:09:27 +0000 Subject: [PATCH 16/48] refactor(tests): switch from prism to steady --- scripts/mock | 26 +++++++++++++------------- scripts/test | 16 ++++++++-------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/scripts/mock b/scripts/mock index bcf3b39..00b490b 100755 --- a/scripts/mock +++ b/scripts/mock @@ -19,34 +19,34 @@ fi echo "==> Starting mock server with URL ${URL}" -# Run prism mock on the given spec +# Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version + npm exec --package=@stdy/cli@0.19.3 -- steady --version - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & + npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-query-object-format=brackets "$URL" &> .stdy.log & - # Wait for server to come online (max 30s) + # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" attempts=0 - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + while ! curl --silent --fail "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1; do + if ! kill -0 $! 2>/dev/null; then + echo + cat .stdy.log + exit 1 + fi attempts=$((attempts + 1)) if [ "$attempts" -ge 300 ]; then echo - echo "Timed out waiting for Prism server to start" - cat .prism.log + echo "Timed out waiting for Steady server to start" + cat .stdy.log exit 1 fi echo -n "." sleep 0.1 done - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - echo else - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" + npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 4b777e0..6550fb4 100755 --- a/scripts/test +++ b/scripts/test @@ -9,8 +9,8 @@ GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 +function steady_is_running() { + curl --silent "http://127.0.0.1:4010/_x-steady/health" >/dev/null 2>&1 } kill_server_on_port() { @@ -25,7 +25,7 @@ function is_overriding_api_base_url() { [ -n "$TEST_API_BASE_URL" ] } -if ! is_overriding_api_base_url && ! prism_is_running ; then +if ! is_overriding_api_base_url && ! steady_is_running ; then # When we exit this script, make sure to kill the background mock server process trap 'kill_server_on_port 4010' EXIT @@ -36,19 +36,19 @@ fi if is_overriding_api_base_url ; then echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" +elif ! steady_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Steady server" echo -e "running against your OpenAPI spec." echo echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" + echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.3 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-query-object-format=brackets${NC}" echo exit 1 else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo -e "${GREEN}✔ Mock steady server is running with your OpenAPI spec${NC}" echo fi From 5ead500c3d450d125dee608bc6ec0054e6928e15 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 21 Mar 2026 02:10:54 +0000 Subject: [PATCH 17/48] chore(tests): bump steady to v0.19.4 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 00b490b..f310477 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.3 -- steady --version + npm exec --package=@stdy/cli@0.19.4 -- steady --version - npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.4 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.3 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.4 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 6550fb4..fd809ca 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.3 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.4 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From 1987ab0fcc91f0bebfdf55a94fd5b6c59f3658e3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 21 Mar 2026 02:18:18 +0000 Subject: [PATCH 18/48] chore(tests): bump steady to v0.19.5 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index f310477..54fc791 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.4 -- steady --version + npm exec --package=@stdy/cli@0.19.5 -- steady --version - npm exec --package=@stdy/cli@0.19.4 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.4 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index fd809ca..7f76536 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.4 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.5 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From 5299bea39412364752a5a21800bc9e5837cbce81 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Mar 2026 02:16:18 +0000 Subject: [PATCH 19/48] chore(tests): bump steady to v0.19.6 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 54fc791..0f82c95 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.5 -- steady --version + npm exec --package=@stdy/cli@0.19.6 -- steady --version - npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.5 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 7f76536..4e32349 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.5 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.6 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From 356dd2b76fe8549a90e60013ad72e3fd5683e3cd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 02:05:46 +0000 Subject: [PATCH 20/48] chore(tests): bump steady to v0.19.7 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 0f82c95..3732f8e 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.6 -- steady --version + npm exec --package=@stdy/cli@0.19.7 -- steady --version - npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.6 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 4e32349..a413579 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.6 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" echo exit 1 From 1139ffe0863debae38e8aadda733f777b0c48a72 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 02:24:58 +0000 Subject: [PATCH 21/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 2b39be6..60bb453 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: ca148af6be59ec54295b2c5f852a38d1 +config_hash: e342a96262eaf44c54e8bbb93cc8d7a7 From 5f4df79886f6c6bc6ae960bd1c98e4aa30f41b1e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 02:25:24 +0000 Subject: [PATCH 22/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 60bb453..16d5bba 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: e342a96262eaf44c54e8bbb93cc8d7a7 +config_hash: f99f904573839260bdb6d428bad17613 From e09fc64994169585b967ce426dfd345562f0da49 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 02:25:37 +0000 Subject: [PATCH 23/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 16d5bba..2c47924 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: f99f904573839260bdb6d428bad17613 +config_hash: 7d85c0b454fc78a59db6474c5c4d73c6 From 05282bbbaad46dceff167998b75e34a778f42a24 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Mar 2026 02:09:26 +0000 Subject: [PATCH 24/48] chore(internal): update multipart form array serialization --- scripts/mock | 4 ++-- scripts/test | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/mock b/scripts/mock index 3732f8e..58e4628 100755 --- a/scripts/mock +++ b/scripts/mock @@ -24,7 +24,7 @@ if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout npm exec --package=@stdy/cli@0.19.7 -- steady --version - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index a413579..fcc0156 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-form-array-format=repeat --validator-query-array-format=repeat --validator-form-object-format=brackets --validator-query-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From 9a809f782c368dbed079b96555a27f76f39a9b42 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 02:17:43 +0000 Subject: [PATCH 25/48] chore(tests): bump steady to v0.20.1 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 58e4628..5ea72a2 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.19.7 -- steady --version + npm exec --package=@stdy/cli@0.20.1 -- steady --version - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.20.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.19.7 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.20.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index fcc0156..efbe324 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.19.7 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From 71daf3588b2f471df63c4070b121e8c5587e5727 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 1 Apr 2026 02:22:14 +0000 Subject: [PATCH 26/48] chore(tests): bump steady to v0.20.2 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 5ea72a2..7c58865 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.20.1 -- steady --version + npm exec --package=@stdy/cli@0.20.2 -- steady --version - npm exec --package=@stdy/cli@0.20.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.20.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index efbe324..4f75ee9 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.2 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From 44ea2d6f7210b88dd61b764242e7a68254f07efb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 02:32:53 +0000 Subject: [PATCH 27/48] fix(client): properly generate file params --- README.md | 30 ++++++++++++ src/Assets/AssetUploadParams.php | 7 +-- src/Core/Conversion.php | 4 ++ src/Core/FileParam.php | 63 +++++++++++++++++++++++++ src/Core/Util.php | 60 ++++++++++++++++++----- src/ServiceContracts/AssetsContract.php | 5 +- src/Services/AssetsRawService.php | 3 +- src/Services/AssetsService.php | 5 +- tests/Services/AssetsTest.php | 9 ++-- 9 files changed, 162 insertions(+), 24 deletions(-) create mode 100644 src/Core/FileParam.php diff --git a/README.md b/README.md index a027b75..b030bdc 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,36 @@ $client = new Client(requestOptions: ['maxRetries' => 0]); $result = $client->accounts->list(requestOptions: ['maxRetries' => 5]); ``` +### File uploads + +Request parameters that correspond to file uploads can be passed as a resource returned by `fopen()`, a string of file contents, or a `FileParam` instance. + +```php +assets->upload( + file: FileParam::fromString($contents, filename: '/path/to/file', contentType: '…'), +); + +// Pass in only a string (where applicable) +$response = $client->assets->upload(file: '…'); + +// Pass an open resource: +$fd = fopen('/path/to/file', 'r'); +try { + $response = $client->assets->upload( + file: FileParam::fromResource($fd, filename: '/path/to/file', contentType: '…'), + ); +} finally { + fclose($fd); +} +``` + ## Advanced concepts ### Making custom or undocumented requests diff --git a/src/Assets/AssetUploadParams.php b/src/Assets/AssetUploadParams.php index 81fd455..1d4b690 100644 --- a/src/Assets/AssetUploadParams.php +++ b/src/Assets/AssetUploadParams.php @@ -9,6 +9,7 @@ use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Concerns\SdkParams; use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Core\FileParam; /** * Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending messages with attachments. @@ -16,7 +17,7 @@ * @see BeeperDesktop\Services\AssetsService::upload() * * @phpstan-type AssetUploadParamsShape = array{ - * file: string, fileName?: string|null, mimeType?: string|null + * file: string|FileParam, fileName?: string|null, mimeType?: string|null * } */ final class AssetUploadParams implements BaseModel @@ -68,7 +69,7 @@ public function __construct() * You must use named parameters to construct any parameters with a default value. */ public static function with( - string $file, + string|FileParam $file, ?string $fileName = null, ?string $mimeType = null ): self { @@ -85,7 +86,7 @@ public static function with( /** * The file to upload (max 500 MB). */ - public function withFile(string $file): self + public function withFile(string|FileParam $file): self { $self = clone $this; $self['file'] = $file; diff --git a/src/Core/Conversion.php b/src/Core/Conversion.php index b903d2f..5dee0ee 100644 --- a/src/Core/Conversion.php +++ b/src/Core/Conversion.php @@ -21,6 +21,10 @@ public static function dump_unknown(mixed $value, DumpState $state): mixed } if (is_object($value)) { + if ($value instanceof FileParam) { + return $value; + } + if (is_a($value, class: ConverterSource::class)) { return $value::converter()->dump($value, state: $state); } diff --git a/src/Core/FileParam.php b/src/Core/FileParam.php new file mode 100644 index 0000000..eb8db4a --- /dev/null +++ b/src/Core/FileParam.php @@ -0,0 +1,63 @@ +files->upload(file: FileParam::fromResource(fopen('data.csv', 'r'))); + * + * // From a string: + * $client->files->upload(file: FileParam::fromString('csv data...', 'data.csv')); + * ``` + */ +final class FileParam +{ + public const DEFAULT_CONTENT_TYPE = 'application/octet-stream'; + + /** + * @param resource|string $data the file content as a resource or string + */ + private function __construct( + public readonly mixed $data, + public readonly string $filename, + public readonly string $contentType = self::DEFAULT_CONTENT_TYPE, + ) {} + + /** + * Create a FileParam from an open resource (e.g. from fopen()). + * + * @param resource $resource an open file resource + * @param string|null $filename Override the filename. Defaults to the resource URI basename. + * @param string $contentType override the content type + */ + public static function fromResource(mixed $resource, ?string $filename = null, string $contentType = self::DEFAULT_CONTENT_TYPE): self + { + if (!is_resource($resource)) { + throw new \InvalidArgumentException('Expected a resource, got '.get_debug_type($resource)); + } + + if (null === $filename) { + $meta = stream_get_meta_data($resource); + $filename = basename($meta['uri'] ?? 'upload'); + } + + return new self($resource, filename: $filename, contentType: $contentType); + } + + /** + * Create a FileParam from a string. + * + * @param string $content the file content + * @param string $filename the filename for the Content-Disposition header + * @param string $contentType override the content type + */ + public static function fromString(string $content, string $filename, string $contentType = self::DEFAULT_CONTENT_TYPE): self + { + return new self($content, filename: $filename, contentType: $contentType); + } +} diff --git a/src/Core/Util.php b/src/Core/Util.php index 35a9a0b..b385aff 100644 --- a/src/Core/Util.php +++ b/src/Core/Util.php @@ -283,7 +283,7 @@ public static function withSetBody( if (preg_match('/^multipart\/form-data/', $contentType)) { [$boundary, $gen] = self::encodeMultipartStreaming($body); - $encoded = implode('', iterator_to_array($gen)); + $encoded = implode('', iterator_to_array($gen, preserve_keys: false)); $stream = $factory->createStream($encoded); /** @var RequestInterface */ @@ -447,11 +447,18 @@ private static function writeMultipartContent( ): \Generator { $contentLine = "Content-Type: %s\r\n\r\n"; - if (is_resource($val)) { - yield sprintf($contentLine, $contentType ?? 'application/octet-stream'); - while (!feof($val)) { - if ($read = fread($val, length: self::BUF_SIZE)) { - yield $read; + if ($val instanceof FileParam) { + $ct = $val->contentType ?? $contentType; + + yield sprintf($contentLine, $ct); + $data = $val->data; + if (is_string($data)) { + yield $data; + } else { // resource + while (!feof($data)) { + if ($read = fread($data, length: self::BUF_SIZE)) { + yield $read; + } } } } elseif (is_string($val) || is_numeric($val) || is_bool($val)) { @@ -483,17 +490,48 @@ private static function writeMultipartChunk( yield 'Content-Disposition: form-data'; if (!is_null($key)) { - $name = rawurlencode(self::strVal($key)); + $name = str_replace(['"', "\r", "\n"], replace: '', subject: $key); yield "; name=\"{$name}\""; } + // File uploads require a filename in the Content-Disposition header, + // e.g. `Content-Disposition: form-data; name="file"; filename="data.csv"` + // Without this, many servers will reject the upload with a 400. + if ($val instanceof FileParam) { + $filename = str_replace(['"', "\r", "\n"], replace: '', subject: $val->filename); + + yield "; filename=\"{$filename}\""; + } + yield "\r\n"; foreach (self::writeMultipartContent($val, closing: $closing) as $chunk) { yield $chunk; } } + /** + * Expands list arrays into separate multipart parts, applying the configured array key format. + * + * @param list $closing + * + * @return \Generator + */ + private static function writeMultipartField( + string $boundary, + ?string $key, + mixed $val, + array &$closing + ): \Generator { + if (is_array($val) && array_is_list($val)) { + foreach ($val as $item) { + yield from self::writeMultipartField(boundary: $boundary, key: $key, val: $item, closing: $closing); + } + } else { + yield from self::writeMultipartChunk(boundary: $boundary, key: $key, val: $val, closing: $closing); + } + } + /** * @param bool|int|float|string|resource|\Traversable|array|null $body * @@ -508,14 +546,10 @@ private static function encodeMultipartStreaming(mixed $body): array try { if (is_array($body) || is_object($body)) { foreach ((array) $body as $key => $val) { - foreach (static::writeMultipartChunk(boundary: $boundary, key: $key, val: $val, closing: $closing) as $chunk) { - yield $chunk; - } + yield from static::writeMultipartField(boundary: $boundary, key: $key, val: $val, closing: $closing); } } else { - foreach (static::writeMultipartChunk(boundary: $boundary, key: null, val: $body, closing: $closing) as $chunk) { - yield $chunk; - } + yield from static::writeMultipartField(boundary: $boundary, key: null, val: $body, closing: $closing); } yield "--{$boundary}--\r\n"; diff --git a/src/ServiceContracts/AssetsContract.php b/src/ServiceContracts/AssetsContract.php index 6064d5b..dff92bd 100644 --- a/src/ServiceContracts/AssetsContract.php +++ b/src/ServiceContracts/AssetsContract.php @@ -8,6 +8,7 @@ use BeeperDesktop\Assets\AssetUploadBase64Response; use BeeperDesktop\Assets\AssetUploadResponse; use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\FileParam; use BeeperDesktop\RequestOptions; /** @@ -44,7 +45,7 @@ public function serve( /** * @api * - * @param string $file the file to upload (max 500 MB) + * @param string|FileParam $file the file to upload (max 500 MB) * @param string $fileName Original filename. Defaults to the uploaded file name if omitted * @param string $mimeType MIME type. Auto-detected from magic bytes if omitted * @param RequestOpts|null $requestOptions @@ -52,7 +53,7 @@ public function serve( * @throws APIException */ public function upload( - string $file, + string|FileParam $file, ?string $fileName = null, ?string $mimeType = null, RequestOptions|array|null $requestOptions = null, diff --git a/src/Services/AssetsRawService.php b/src/Services/AssetsRawService.php index 051bf2a..22d415c 100644 --- a/src/Services/AssetsRawService.php +++ b/src/Services/AssetsRawService.php @@ -14,6 +14,7 @@ use BeeperDesktop\Client; use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\FileParam; use BeeperDesktop\RequestOptions; use BeeperDesktop\ServiceContracts\AssetsRawContract; @@ -98,7 +99,7 @@ public function serve( * Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending messages with attachments. * * @param array{ - * file: string, fileName?: string, mimeType?: string + * file: string|FileParam, fileName?: string, mimeType?: string * }|AssetUploadParams $params * @param RequestOpts|null $requestOptions * diff --git a/src/Services/AssetsService.php b/src/Services/AssetsService.php index 6d77b41..4027449 100644 --- a/src/Services/AssetsService.php +++ b/src/Services/AssetsService.php @@ -9,6 +9,7 @@ use BeeperDesktop\Assets\AssetUploadResponse; use BeeperDesktop\Client; use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\FileParam; use BeeperDesktop\Core\Util; use BeeperDesktop\RequestOptions; use BeeperDesktop\ServiceContracts\AssetsContract; @@ -82,7 +83,7 @@ public function serve( * * Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending messages with attachments. * - * @param string $file the file to upload (max 500 MB) + * @param string|FileParam $file the file to upload (max 500 MB) * @param string $fileName Original filename. Defaults to the uploaded file name if omitted * @param string $mimeType MIME type. Auto-detected from magic bytes if omitted * @param RequestOpts|null $requestOptions @@ -90,7 +91,7 @@ public function serve( * @throws APIException */ public function upload( - string $file, + string|FileParam $file, ?string $fileName = null, ?string $mimeType = null, RequestOptions|array|null $requestOptions = null, diff --git a/tests/Services/AssetsTest.php b/tests/Services/AssetsTest.php index 4ae3576..09c9a2e 100644 --- a/tests/Services/AssetsTest.php +++ b/tests/Services/AssetsTest.php @@ -6,6 +6,7 @@ use BeeperDesktop\Assets\AssetUploadBase64Response; use BeeperDesktop\Assets\AssetUploadResponse; use BeeperDesktop\Client; +use BeeperDesktop\Core\FileParam; use BeeperDesktop\Core\Util; use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\Test; @@ -72,7 +73,9 @@ public function testServeWithOptionalParams(): void #[Test] public function testUpload(): void { - $result = $this->client->assets->upload(file: 'file'); + $result = $this->client->assets->upload( + file: FileParam::fromString('Example data', filename: uniqid('file-upload-', true)), + ); // @phpstan-ignore-next-line method.alreadyNarrowedType $this->assertInstanceOf(AssetUploadResponse::class, $result); @@ -82,9 +85,9 @@ public function testUpload(): void public function testUploadWithOptionalParams(): void { $result = $this->client->assets->upload( - file: 'file', + file: FileParam::fromString('Example data', filename: uniqid('file-upload-', true)), fileName: 'fileName', - mimeType: 'mimeType' + mimeType: 'mimeType', ); // @phpstan-ignore-next-line method.alreadyNarrowedType From 8b250446d8d538fc1027c9df483f07034049e302 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 12 Apr 2026 18:31:47 +0000 Subject: [PATCH 28/48] feat(api): add network, bridge fields to accounts --- .stats.yml | 6 +- README.md | 10 +- src/Accounts/Account.php | 64 +++++- src/Accounts/Account/Bridge.php | 118 ++++++++++ src/Accounts/Account/Bridge/Provider.php | 19 ++ src/Chats/ChatCreateParams.php | 203 ++---------------- src/Chats/ChatCreateParams/Params.php | 31 +++ .../ChatCreateParams/Params/UnionMember0.php | 166 ++++++++++++++ .../Params/UnionMember0/Mode.php | 13 ++ .../{ => Params/UnionMember0}/User.php | 4 +- .../ChatCreateParams/Params/UnionMember1.php | 191 ++++++++++++++++ .../{ => Params/UnionMember1}/Mode.php | 4 +- .../Params/UnionMember1/Type.php | 15 ++ src/Chats/ChatCreateParams/Type.php | 15 -- src/ServiceContracts/ChatsContract.php | 30 +-- src/Services/ChatsRawService.php | 21 +- src/Services/ChatsService.php | 45 +--- tests/Services/ChatsTest.php | 26 +-- 18 files changed, 661 insertions(+), 320 deletions(-) create mode 100644 src/Accounts/Account/Bridge.php create mode 100644 src/Accounts/Account/Bridge/Provider.php create mode 100644 src/Chats/ChatCreateParams/Params.php create mode 100644 src/Chats/ChatCreateParams/Params/UnionMember0.php create mode 100644 src/Chats/ChatCreateParams/Params/UnionMember0/Mode.php rename src/Chats/ChatCreateParams/{ => Params/UnionMember0}/User.php (94%) create mode 100644 src/Chats/ChatCreateParams/Params/UnionMember1.php rename src/Chats/ChatCreateParams/{ => Params/UnionMember1}/Mode.php (66%) create mode 100644 src/Chats/ChatCreateParams/Params/UnionMember1/Type.php delete mode 100644 src/Chats/ChatCreateParams/Type.php diff --git a/.stats.yml b/.stats.yml index 2c47924..229f6b5 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-5a8ac7b545c48dc892e5c680303e305254921554dabee848e40a808659dbcf1e.yml -openapi_spec_hash: 0103975601aac1445d3a4ef418c5d17a -config_hash: 7d85c0b454fc78a59db6474c5c4d73c6 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper%2Fbeeper-desktop-api-611aa7641fbca8cf31d626bf86f9efd3c2b92778e897ebbb25c6ea44185ed1ed.yml +openapi_spec_hash: d6c0a1776048dab04f6c5625c9893c9c +config_hash: 39ed0717b5f415499aaace2468346e1a diff --git a/README.md b/README.md index b030bdc..e90f056 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ The Beeper Desktop PHP library provides convenient access to the Beeper Desktop REST API from any PHP 8.1.0+ application. -It is generated with [Stainless](https://www.stainless.com/). - ## Documentation The REST API documentation can be found on [developers.beeper.com](https://developers.beeper.com/desktop-api/). @@ -40,7 +38,9 @@ Parameters with a default value must be set by name. use BeeperDesktop\Client; -$client = new Client(); +$client = new Client( + accessToken: getenv('BEEPER_ACCESS_TOKEN') ?: 'My Access Token' +); $page = $client->chats->search(includeMuted: true, limit: 3, type: 'single'); @@ -65,7 +65,9 @@ This library provides auto-paginating iterators with each list response, so you use BeeperDesktop\Client; -$client = new Client(); +$client = new Client( + accessToken: getenv('BEEPER_ACCESS_TOKEN') ?: 'My Access Token' +); $page = $client->messages->search( accountIDs: ['local-telegram_ba_QFrb5lrLPhO3OT5MFBeTWv0x4BI'], diff --git a/src/Accounts/Account.php b/src/Accounts/Account.php index 270cb3e..174a24a 100644 --- a/src/Accounts/Account.php +++ b/src/Accounts/Account.php @@ -4,6 +4,7 @@ namespace BeeperDesktop\Accounts; +use BeeperDesktop\Accounts\Account\Bridge; use BeeperDesktop\Core\Attributes\Required; use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Contracts\BaseModel; @@ -12,9 +13,15 @@ /** * A chat account added to Beeper. * + * @phpstan-import-type BridgeShape from \BeeperDesktop\Accounts\Account\Bridge * @phpstan-import-type UserShape from \BeeperDesktop\User * - * @phpstan-type AccountShape = array{accountID: string, user: User|UserShape} + * @phpstan-type AccountShape = array{ + * accountID: string, + * bridge: Bridge|BridgeShape, + * network: string, + * user: User|UserShape, + * } */ final class Account implements BaseModel { @@ -27,6 +34,18 @@ final class Account implements BaseModel #[Required] public string $accountID; + /** + * Bridge metadata for the account. Available from Beeper Desktop v.4.2.719+. + */ + #[Required] + public Bridge $bridge; + + /** + * Human-friendly network name for the account. + */ + #[Required] + public string $network; + /** * User the account belongs to. */ @@ -38,13 +57,17 @@ final class Account implements BaseModel * * To enforce required parameters use * ``` - * Account::with(accountID: ..., user: ...) + * Account::with(accountID: ..., bridge: ..., network: ..., user: ...) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new Account)->withAccountID(...)->withUser(...) + * (new Account) + * ->withAccountID(...) + * ->withBridge(...) + * ->withNetwork(...) + * ->withUser(...) * ``` */ public function __construct() @@ -57,13 +80,20 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * + * @param Bridge|BridgeShape $bridge * @param User|UserShape $user */ - public static function with(string $accountID, User|array $user): self - { + public static function with( + string $accountID, + Bridge|array $bridge, + string $network, + User|array $user + ): self { $self = new self; $self['accountID'] = $accountID; + $self['bridge'] = $bridge; + $self['network'] = $network; $self['user'] = $user; return $self; @@ -80,6 +110,30 @@ public function withAccountID(string $accountID): self return $self; } + /** + * Bridge metadata for the account. Available from Beeper Desktop v.4.2.719+. + * + * @param Bridge|BridgeShape $bridge + */ + public function withBridge(Bridge|array $bridge): self + { + $self = clone $this; + $self['bridge'] = $bridge; + + return $self; + } + + /** + * Human-friendly network name for the account. + */ + public function withNetwork(string $network): self + { + $self = clone $this; + $self['network'] = $network; + + return $self; + } + /** * User the account belongs to. * diff --git a/src/Accounts/Account/Bridge.php b/src/Accounts/Account/Bridge.php new file mode 100644 index 0000000..73b4105 --- /dev/null +++ b/src/Accounts/Account/Bridge.php @@ -0,0 +1,118 @@ +, type: string + * } + */ +final class Bridge implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Bridge instance identifier. + */ + #[Required] + public string $id; + + /** + * Bridge provider for the account. + * + * @var value-of $provider + */ + #[Required(enum: Provider::class)] + public string $provider; + + /** + * Bridge type. + */ + #[Required] + public string $type; + + /** + * `new Bridge()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Bridge::with(id: ..., provider: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Bridge)->withID(...)->withProvider(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Provider|value-of $provider + */ + public static function with( + string $id, + Provider|string $provider, + string $type + ): self { + $self = new self; + + $self['id'] = $id; + $self['provider'] = $provider; + $self['type'] = $type; + + return $self; + } + + /** + * Bridge instance identifier. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * Bridge provider for the account. + * + * @param Provider|value-of $provider + */ + public function withProvider(Provider|string $provider): self + { + $self = clone $this; + $self['provider'] = $provider; + + return $self; + } + + /** + * Bridge type. + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } +} diff --git a/src/Accounts/Account/Bridge/Provider.php b/src/Accounts/Account/Bridge/Provider.php new file mode 100644 index 0000000..59ca678 --- /dev/null +++ b/src/Accounts/Account/Bridge/Provider.php @@ -0,0 +1,19 @@ +, - * participantIDs?: list|null, - * title?: string|null, - * type?: null|Type|value-of, - * user?: null|User|UserShape, - * } + * @phpstan-type ChatCreateParamsShape = array{params?: ParamsShape|null} */ final class ChatCreateParams implements BaseModel { @@ -37,74 +27,10 @@ final class ChatCreateParams implements BaseModel use SdkModel; use SdkParams; - /** - * Account to create or start the chat on. - */ - #[Required] - public string $accountID; - - /** - * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. - */ - #[Optional] - public ?bool $allowInvite; - - /** - * Optional first message content if the platform requires it to create the chat. - */ - #[Optional] - public ?string $messageText; - - /** - * Operation mode. Defaults to 'create' when omitted. - * - * @var value-of|null $mode - */ - #[Optional(enum: Mode::class)] - public ?string $mode; - - /** - * Required when mode='create'. User IDs to include in the new chat. - * - * @var list|null $participantIDs - */ - #[Optional(list: 'string')] - public ?array $participantIDs; - - /** - * Optional title for group chats when mode='create'; ignored for single chats on most platforms. - */ - #[Optional] - public ?string $title; - - /** - * Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. - * - * @var value-of|null $type - */ - #[Optional(enum: Type::class)] - public ?string $type; - - /** - * Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. - */ + /** @var ParamsVariants|null $params */ #[Optional] - public ?User $user; + public UnionMember0|UnionMember1|null $params; - /** - * `new ChatCreateParams()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * ChatCreateParams::with(accountID: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new ChatCreateParams)->withAccountID(...) - * ``` - */ public function __construct() { $this->initialize(); @@ -115,128 +41,25 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param Mode|value-of|null $mode - * @param list|null $participantIDs - * @param Type|value-of|null $type - * @param User|UserShape|null $user + * @param ParamsShape|null $params */ public static function with( - string $accountID, - ?bool $allowInvite = null, - ?string $messageText = null, - Mode|string|null $mode = null, - ?array $participantIDs = null, - ?string $title = null, - Type|string|null $type = null, - User|array|null $user = null, + UnionMember0|array|UnionMember1|null $params = null ): self { $self = new self; - $self['accountID'] = $accountID; - - null !== $allowInvite && $self['allowInvite'] = $allowInvite; - null !== $messageText && $self['messageText'] = $messageText; - null !== $mode && $self['mode'] = $mode; - null !== $participantIDs && $self['participantIDs'] = $participantIDs; - null !== $title && $self['title'] = $title; - null !== $type && $self['type'] = $type; - null !== $user && $self['user'] = $user; - - return $self; - } - - /** - * Account to create or start the chat on. - */ - public function withAccountID(string $accountID): self - { - $self = clone $this; - $self['accountID'] = $accountID; + null !== $params && $self['params'] = $params; return $self; } /** - * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. - */ - public function withAllowInvite(bool $allowInvite): self - { - $self = clone $this; - $self['allowInvite'] = $allowInvite; - - return $self; - } - - /** - * Optional first message content if the platform requires it to create the chat. - */ - public function withMessageText(string $messageText): self - { - $self = clone $this; - $self['messageText'] = $messageText; - - return $self; - } - - /** - * Operation mode. Defaults to 'create' when omitted. - * - * @param Mode|value-of $mode - */ - public function withMode(Mode|string $mode): self - { - $self = clone $this; - $self['mode'] = $mode; - - return $self; - } - - /** - * Required when mode='create'. User IDs to include in the new chat. - * - * @param list $participantIDs - */ - public function withParticipantIDs(array $participantIDs): self - { - $self = clone $this; - $self['participantIDs'] = $participantIDs; - - return $self; - } - - /** - * Optional title for group chats when mode='create'; ignored for single chats on most platforms. - */ - public function withTitle(string $title): self - { - $self = clone $this; - $self['title'] = $title; - - return $self; - } - - /** - * Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. - * - * @param Type|value-of $type - */ - public function withType(Type|string $type): self - { - $self = clone $this; - $self['type'] = $type; - - return $self; - } - - /** - * Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. - * - * @param User|UserShape $user + * @param ParamsShape $params */ - public function withUser(User|array $user): self + public function withParams(UnionMember0|array|UnionMember1 $params): self { $self = clone $this; - $self['user'] = $user; + $self['params'] = $params; return $self; } diff --git a/src/Chats/ChatCreateParams/Params.php b/src/Chats/ChatCreateParams/Params.php new file mode 100644 index 0000000..3a23659 --- /dev/null +++ b/src/Chats/ChatCreateParams/Params.php @@ -0,0 +1,31 @@ +|array + */ + public static function variants(): array + { + return [UnionMember0::class, UnionMember1::class]; + } +} diff --git a/src/Chats/ChatCreateParams/Params/UnionMember0.php b/src/Chats/ChatCreateParams/Params/UnionMember0.php new file mode 100644 index 0000000..21194f4 --- /dev/null +++ b/src/Chats/ChatCreateParams/Params/UnionMember0.php @@ -0,0 +1,166 @@ +, + * user: User|UserShape, + * allowInvite?: bool|null, + * messageText?: string|null, + * } + */ +final class UnionMember0 implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Account to create or start the chat on. + */ + #[Required] + public string $accountID; + + /** + * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. + * + * @var value-of $mode + */ + #[Required(enum: Mode::class)] + public string $mode; + + /** + * Merged user-like contact payload used to resolve the best identifier. + */ + #[Required] + public User $user; + + /** + * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. + */ + #[Optional] + public ?bool $allowInvite; + + /** + * Optional first message content if the platform requires it to create the chat. + */ + #[Optional] + public ?string $messageText; + + /** + * `new UnionMember0()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember0::with(accountID: ..., mode: ..., user: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember0)->withAccountID(...)->withMode(...)->withUser(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Mode|value-of $mode + * @param User|UserShape $user + */ + public static function with( + string $accountID, + Mode|string $mode, + User|array $user, + ?bool $allowInvite = null, + ?string $messageText = null, + ): self { + $self = new self; + + $self['accountID'] = $accountID; + $self['mode'] = $mode; + $self['user'] = $user; + + null !== $allowInvite && $self['allowInvite'] = $allowInvite; + null !== $messageText && $self['messageText'] = $messageText; + + return $self; + } + + /** + * Account to create or start the chat on. + */ + public function withAccountID(string $accountID): self + { + $self = clone $this; + $self['accountID'] = $accountID; + + return $self; + } + + /** + * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. + * + * @param Mode|value-of $mode + */ + public function withMode(Mode|string $mode): self + { + $self = clone $this; + $self['mode'] = $mode; + + return $self; + } + + /** + * Merged user-like contact payload used to resolve the best identifier. + * + * @param User|UserShape $user + */ + public function withUser(User|array $user): self + { + $self = clone $this; + $self['user'] = $user; + + return $self; + } + + /** + * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. + */ + public function withAllowInvite(bool $allowInvite): self + { + $self = clone $this; + $self['allowInvite'] = $allowInvite; + + return $self; + } + + /** + * Optional first message content if the platform requires it to create the chat. + */ + public function withMessageText(string $messageText): self + { + $self = clone $this; + $self['messageText'] = $messageText; + + return $self; + } +} diff --git a/src/Chats/ChatCreateParams/Params/UnionMember0/Mode.php b/src/Chats/ChatCreateParams/Params/UnionMember0/Mode.php new file mode 100644 index 0000000..6fd34d7 --- /dev/null +++ b/src/Chats/ChatCreateParams/Params/UnionMember0/Mode.php @@ -0,0 +1,13 @@ +, + * type: Type|value-of, + * messageText?: string|null, + * mode?: null|Mode|value-of, + * title?: string|null, + * } + */ +final class UnionMember1 implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Account to create or start the chat on. + */ + #[Required] + public string $accountID; + + /** + * User IDs to include in the new chat. + * + * @var list $participantIDs + */ + #[Required(list: 'string')] + public array $participantIDs; + + /** + * 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. + * + * @var value-of $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * Optional first message content if the platform requires it to create the chat. + */ + #[Optional] + public ?string $messageText; + + /** + * Operation mode. Defaults to 'create' when omitted. + * + * @var value-of|null $mode + */ + #[Optional(enum: Mode::class)] + public ?string $mode; + + /** + * Optional title for group chats; ignored for single chats on most platforms. + */ + #[Optional] + public ?string $title; + + /** + * `new UnionMember1()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember1::with(accountID: ..., participantIDs: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember1)->withAccountID(...)->withParticipantIDs(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list $participantIDs + * @param Type|value-of $type + * @param Mode|value-of|null $mode + */ + public static function with( + string $accountID, + array $participantIDs, + Type|string $type, + ?string $messageText = null, + Mode|string|null $mode = null, + ?string $title = null, + ): self { + $self = new self; + + $self['accountID'] = $accountID; + $self['participantIDs'] = $participantIDs; + $self['type'] = $type; + + null !== $messageText && $self['messageText'] = $messageText; + null !== $mode && $self['mode'] = $mode; + null !== $title && $self['title'] = $title; + + return $self; + } + + /** + * Account to create or start the chat on. + */ + public function withAccountID(string $accountID): self + { + $self = clone $this; + $self['accountID'] = $accountID; + + return $self; + } + + /** + * User IDs to include in the new chat. + * + * @param list $participantIDs + */ + public function withParticipantIDs(array $participantIDs): self + { + $self = clone $this; + $self['participantIDs'] = $participantIDs; + + return $self; + } + + /** + * 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Optional first message content if the platform requires it to create the chat. + */ + public function withMessageText(string $messageText): self + { + $self = clone $this; + $self['messageText'] = $messageText; + + return $self; + } + + /** + * Operation mode. Defaults to 'create' when omitted. + * + * @param Mode|value-of $mode + */ + public function withMode(Mode|string $mode): self + { + $self = clone $this; + $self['mode'] = $mode; + + return $self; + } + + /** + * Optional title for group chats; ignored for single chats on most platforms. + */ + public function withTitle(string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } +} diff --git a/src/Chats/ChatCreateParams/Mode.php b/src/Chats/ChatCreateParams/Params/UnionMember1/Mode.php similarity index 66% rename from src/Chats/ChatCreateParams/Mode.php rename to src/Chats/ChatCreateParams/Params/UnionMember1/Mode.php index 8ade752..bd342be 100644 --- a/src/Chats/ChatCreateParams/Mode.php +++ b/src/Chats/ChatCreateParams/Params/UnionMember1/Mode.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace BeeperDesktop\Chats\ChatCreateParams; +namespace BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember1; /** * Operation mode. Defaults to 'create' when omitted. @@ -10,6 +10,4 @@ enum Mode: string { case CREATE = 'create'; - - case START = 'start'; } diff --git a/src/Chats/ChatCreateParams/Params/UnionMember1/Type.php b/src/Chats/ChatCreateParams/Params/UnionMember1/Type.php new file mode 100644 index 0000000..fe89d65 --- /dev/null +++ b/src/Chats/ChatCreateParams/Params/UnionMember1/Type.php @@ -0,0 +1,15 @@ + $mode Operation mode. Defaults to 'create' when omitted. - * @param list $participantIDs Required when mode='create'. User IDs to include in the new chat. - * @param string $title optional title for group chats when mode='create'; ignored for single chats on most platforms - * @param Type|value-of $type Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. - * @param User|UserShape $user Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. + * @param ParamsShape $params * @param RequestOpts|null $requestOptions * * @throws APIException */ public function create( - string $accountID, - bool $allowInvite = true, - ?string $messageText = null, - Mode|string|null $mode = null, - ?array $participantIDs = null, - ?string $title = null, - Type|string|null $type = null, - User|array|null $user = null, + UnionMember0|array|UnionMember1|null $params = null, RequestOptions|array|null $requestOptions = null, ): ChatNewResponse; @@ -113,7 +99,7 @@ public function archive( * @param int $limit Set the maximum number of chats to retrieve. Valid range: 1-200, default is 50 * @param string $query Literal token search (non-semantic). Use single words users type (e.g., "dinner"). When multiple words provided, ALL must match. Case-insensitive. * @param Scope|value-of $scope search scope: 'titles' matches title + network; 'participants' matches participant names - * @param \BeeperDesktop\Chats\ChatSearchParams\Type|value-of<\BeeperDesktop\Chats\ChatSearchParams\Type> $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types + * @param Type|value-of $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types * @param bool|null $unreadOnly Set to true to only retrieve chats that have unread messages * @param RequestOpts|null $requestOptions * @@ -132,7 +118,7 @@ public function search( int $limit = 50, ?string $query = null, Scope|string $scope = 'titles', - \BeeperDesktop\Chats\ChatSearchParams\Type|string $type = 'any', + Type|string $type = 'any', ?bool $unreadOnly = null, RequestOptions|array|null $requestOptions = null, ): CursorSearch; diff --git a/src/Services/ChatsRawService.php b/src/Services/ChatsRawService.php index d54d92b..34751aa 100644 --- a/src/Services/ChatsRawService.php +++ b/src/Services/ChatsRawService.php @@ -7,9 +7,6 @@ use BeeperDesktop\Chats\Chat; use BeeperDesktop\Chats\ChatArchiveParams; use BeeperDesktop\Chats\ChatCreateParams; -use BeeperDesktop\Chats\ChatCreateParams\Mode; -use BeeperDesktop\Chats\ChatCreateParams\Type; -use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Chats\ChatListParams; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; @@ -18,6 +15,7 @@ use BeeperDesktop\Chats\ChatSearchParams; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; +use BeeperDesktop\Chats\ChatSearchParams\Type; use BeeperDesktop\Client; use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; @@ -29,7 +27,7 @@ /** * Manage chats. * - * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User + * @phpstan-import-type ParamsShape from \BeeperDesktop\Chats\ChatCreateParams\Params * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class ChatsRawService implements ChatsRawContract @@ -45,16 +43,7 @@ public function __construct(private Client $client) {} * * Create a single/group chat (mode='create') or start a direct chat from merged user data (mode='start'). * - * @param array{ - * accountID: string, - * allowInvite?: bool, - * messageText?: string, - * mode?: Mode|value-of, - * participantIDs?: list, - * title?: string, - * type?: Type|value-of, - * user?: User|UserShape, - * }|ChatCreateParams $params + * @param array{params?: ParamsShape}|ChatCreateParams $params * @param RequestOpts|null $requestOptions * * @return BaseResponse @@ -74,7 +63,7 @@ public function create( return $this->client->request( method: 'post', path: 'v1/chats', - body: (object) $parsed, + body: (object) $parsed['params'], options: $options, convert: ChatNewResponse::class, ); @@ -198,7 +187,7 @@ public function archive( * limit?: int, * query?: string, * scope?: Scope|value-of, - * type?: ChatSearchParams\Type|value-of, + * type?: Type|value-of, * unreadOnly?: bool|null, * }|ChatSearchParams $params * @param RequestOpts|null $requestOptions diff --git a/src/Services/ChatsService.php b/src/Services/ChatsService.php index fbeb607..b103c76 100644 --- a/src/Services/ChatsService.php +++ b/src/Services/ChatsService.php @@ -5,14 +5,14 @@ namespace BeeperDesktop\Services; use BeeperDesktop\Chats\Chat; -use BeeperDesktop\Chats\ChatCreateParams\Mode; -use BeeperDesktop\Chats\ChatCreateParams\Type; -use BeeperDesktop\Chats\ChatCreateParams\User; +use BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember0; +use BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember1; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; use BeeperDesktop\Chats\ChatNewResponse; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; +use BeeperDesktop\Chats\ChatSearchParams\Type; use BeeperDesktop\Client; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\Core\Util; @@ -26,7 +26,7 @@ /** * Manage chats. * - * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User + * @phpstan-import-type ParamsShape from \BeeperDesktop\Chats\ChatCreateParams\Params * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class ChatsService implements ChatsContract @@ -61,44 +61,19 @@ public function __construct(private Client $client) * * Create a single/group chat (mode='create') or start a direct chat from merged user data (mode='start'). * - * @param string $accountID account to create or start the chat on - * @param bool $allowInvite Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. - * @param string $messageText optional first message content if the platform requires it to create the chat - * @param Mode|value-of $mode Operation mode. Defaults to 'create' when omitted. - * @param list $participantIDs Required when mode='create'. User IDs to include in the new chat. - * @param string $title optional title for group chats when mode='create'; ignored for single chats on most platforms - * @param Type|value-of $type Required when mode='create'. 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. - * @param User|UserShape $user Required when mode='start'. Merged user-like contact payload used to resolve the best identifier. + * @param ParamsShape $params * @param RequestOpts|null $requestOptions * * @throws APIException */ public function create( - string $accountID, - bool $allowInvite = true, - ?string $messageText = null, - Mode|string|null $mode = null, - ?array $participantIDs = null, - ?string $title = null, - Type|string|null $type = null, - User|array|null $user = null, + UnionMember0|array|UnionMember1|null $params = null, RequestOptions|array|null $requestOptions = null, ): ChatNewResponse { - $params = Util::removeNulls( - [ - 'accountID' => $accountID, - 'allowInvite' => $allowInvite, - 'messageText' => $messageText, - 'mode' => $mode, - 'participantIDs' => $participantIDs, - 'title' => $title, - 'type' => $type, - 'user' => $user, - ], - ); + $params1 = Util::removeNulls(['params' => $params]); // @phpstan-ignore-next-line argument.type - $response = $this->raw->create(params: $params, requestOptions: $requestOptions); + $response = $this->raw->create(params: $params1, requestOptions: $requestOptions); return $response->parse(); } @@ -202,7 +177,7 @@ public function archive( * @param int $limit Set the maximum number of chats to retrieve. Valid range: 1-200, default is 50 * @param string $query Literal token search (non-semantic). Use single words users type (e.g., "dinner"). When multiple words provided, ALL must match. Case-insensitive. * @param Scope|value-of $scope search scope: 'titles' matches title + network; 'participants' matches participant names - * @param \BeeperDesktop\Chats\ChatSearchParams\Type|value-of<\BeeperDesktop\Chats\ChatSearchParams\Type> $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types + * @param Type|value-of $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types * @param bool|null $unreadOnly Set to true to only retrieve chats that have unread messages * @param RequestOpts|null $requestOptions * @@ -221,7 +196,7 @@ public function search( int $limit = 50, ?string $query = null, Scope|string $scope = 'titles', - \BeeperDesktop\Chats\ChatSearchParams\Type|string $type = 'any', + Type|string $type = 'any', ?bool $unreadOnly = null, RequestOptions|array|null $requestOptions = null, ): CursorSearch { diff --git a/tests/Services/ChatsTest.php b/tests/Services/ChatsTest.php index 6678d05..5ead909 100644 --- a/tests/Services/ChatsTest.php +++ b/tests/Services/ChatsTest.php @@ -34,31 +34,7 @@ protected function setUp(): void #[Test] public function testCreate(): void { - $result = $this->client->chats->create(accountID: 'accountID'); - - // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertInstanceOf(ChatNewResponse::class, $result); - } - - #[Test] - public function testCreateWithOptionalParams(): void - { - $result = $this->client->chats->create( - accountID: 'accountID', - allowInvite: true, - messageText: 'messageText', - mode: 'create', - participantIDs: ['string'], - title: 'title', - type: 'single', - user: [ - 'id' => 'id', - 'email' => 'email', - 'fullName' => 'fullName', - 'phoneNumber' => 'phoneNumber', - 'username' => 'username', - ], - ); + $result = $this->client->chats->create(); // @phpstan-ignore-next-line method.alreadyNarrowedType $this->assertInstanceOf(ChatNewResponse::class, $result); From 7d947c2190514f5039947136a1e795e69069d42b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:30:56 +0000 Subject: [PATCH 29/48] fix(client): resolve serialization issue with unions and enums --- src/Core/Attributes/Required.php | 17 +---------------- src/Core/Conversion.php | 15 +++++++++++++++ src/Core/Conversion/EnumOf.php | 15 +++++++++++++-- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/Core/Attributes/Required.php b/src/Core/Attributes/Required.php index bcb6957..d861eb6 100644 --- a/src/Core/Attributes/Required.php +++ b/src/Core/Attributes/Required.php @@ -25,9 +25,6 @@ class Required public readonly bool $nullable; - /** @var array */ - private static array $enumConverters = []; - /** * @param class-string|Converter|string|null $type * @param class-string<\BackedEnum>|Converter|null $enum @@ -52,7 +49,7 @@ public function __construct( $type ??= new MapOf($map); } if (null !== $enum) { - $type ??= $enum instanceof Converter ? $enum : self::enumConverter($enum); + $type ??= $enum instanceof Converter ? $enum : EnumOf::fromBackedEnum($enum); } $this->apiName = $apiName; @@ -60,16 +57,4 @@ public function __construct( $this->optional = false; $this->nullable = $nullable; } - - /** @property class-string<\BackedEnum> $enum */ - private static function enumConverter(string $enum): Converter - { - if (!isset(self::$enumConverters[$enum])) { - // @phpstan-ignore-next-line argument.type - $converter = new EnumOf(array_column($enum::cases(), column_key: 'value')); - self::$enumConverters[$enum] = $converter; - } - - return self::$enumConverters[$enum]; - } } diff --git a/src/Core/Conversion.php b/src/Core/Conversion.php index 5dee0ee..84a6f56 100644 --- a/src/Core/Conversion.php +++ b/src/Core/Conversion.php @@ -8,6 +8,7 @@ use BeeperDesktop\Core\Conversion\Contracts\Converter; use BeeperDesktop\Core\Conversion\Contracts\ConverterSource; use BeeperDesktop\Core\Conversion\DumpState; +use BeeperDesktop\Core\Conversion\EnumOf; /** * @internal @@ -65,6 +66,13 @@ public static function coerce(Converter|ConverterSource|string $target, mixed $v return $target->coerce($value, state: $state); } + // BackedEnum class-name targets: wrap in EnumOf so enum values are scored + // against the enum's cases. Without this, tryConvert's default case scores + // any class-name target as `no`, even when the value is a valid enum member. + if (is_a($target, class: \BackedEnum::class, allow_string: true)) { + return EnumOf::fromBackedEnum($target)->coerce($value, state: $state); + } + return self::tryConvert($target, value: $value, state: $state); } @@ -78,6 +86,13 @@ public static function dump(Converter|ConverterSource|string $target, mixed $val return $target::converter()->dump($value, state: $state); } + // BackedEnum class-name targets: wrap in EnumOf so enum values are scored + // against the enum's cases. Without this, tryConvert's default case scores + // any class-name target as `no`, even when the value is a valid enum member. + if (is_a($target, class: \BackedEnum::class, allow_string: true)) { + return EnumOf::fromBackedEnum($target)->dump($value, state: $state); + } + self::tryConvert($target, value: $value, state: $state); return self::dump_unknown($value, state: $state); diff --git a/src/Core/Conversion/EnumOf.php b/src/Core/Conversion/EnumOf.php index a4d791b..b44c92c 100644 --- a/src/Core/Conversion/EnumOf.php +++ b/src/Core/Conversion/EnumOf.php @@ -14,6 +14,9 @@ final class EnumOf implements Converter { private readonly string $type; + /** @var array, self> */ + private static array $cache = []; + /** * @param list $members */ @@ -26,6 +29,13 @@ public function __construct(private readonly array $members) $this->type = $type; } + /** @param class-string<\BackedEnum> $enum */ + public static function fromBackedEnum(string $enum): self + { + // @phpstan-ignore-next-line argument.type + return self::$cache[$enum] ??= new self(array_column($enum::cases(), column_key: 'value')); + } + public function coerce(mixed $value, CoerceState $state): mixed { $this->tally($value, state: $state); @@ -42,9 +52,10 @@ public function dump(mixed $value, DumpState $state): mixed private function tally(mixed $value, CoerceState|DumpState $state): void { - if (in_array($value, haystack: $this->members, strict: true)) { + $needle = $value instanceof \BackedEnum ? $value->value : $value; + if (in_array($needle, haystack: $this->members, strict: true)) { ++$state->yes; - } elseif ($this->type === gettype($value)) { + } elseif ($this->type === gettype($needle)) { ++$state->maybe; } else { ++$state->no; From 8c3b6fc3be27e61cfb5556fab51f29bff5eae2e6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:32:49 +0000 Subject: [PATCH 30/48] fix: populate enum-typed properties with enum instances --- src/Core/Conversion/EnumOf.php | 20 +++++++++-- tests/Core/ModelTest.php | 62 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/Core/Conversion/EnumOf.php b/src/Core/Conversion/EnumOf.php index b44c92c..c8ce88b 100644 --- a/src/Core/Conversion/EnumOf.php +++ b/src/Core/Conversion/EnumOf.php @@ -19,9 +19,12 @@ final class EnumOf implements Converter /** * @param list $members + * @param class-string<\BackedEnum>|null $class */ - public function __construct(private readonly array $members) - { + public function __construct( + private readonly array $members, + private readonly ?string $class = null, + ) { $type = 'NULL'; foreach ($this->members as $member) { $type = gettype($member); @@ -33,13 +36,24 @@ public function __construct(private readonly array $members) public static function fromBackedEnum(string $enum): self { // @phpstan-ignore-next-line argument.type - return self::$cache[$enum] ??= new self(array_column($enum::cases(), column_key: 'value')); + return self::$cache[$enum] ??= new self( + array_column($enum::cases(), column_key: 'value'), + class: $enum, + ); } public function coerce(mixed $value, CoerceState $state): mixed { $this->tally($value, state: $state); + if ($value instanceof \BackedEnum) { + return $value; + } + + if (null !== $this->class && (is_int($value) || is_string($value))) { + return ($this->class)::tryFrom($value) ?? $value; + } + return $value; } diff --git a/tests/Core/ModelTest.php b/tests/Core/ModelTest.php index 68e6e66..995da87 100644 --- a/tests/Core/ModelTest.php +++ b/tests/Core/ModelTest.php @@ -47,6 +47,30 @@ public function __construct( } } +enum TicketPriority: string +{ + case Low = 'low'; + case High = 'high'; +} + +class Ticket implements BaseModel +{ + /** @use SdkModel> */ + use SdkModel; + + #[Required(enum: TicketPriority::class)] + public TicketPriority $priority; + + /** @var list */ + #[Required(list: TicketPriority::class)] + public array $labels; + + public function __construct() + { + $this->initialize(); + } +} + /** * @internal * @@ -141,4 +165,42 @@ public function testSerializeModelWithExplicitNull(): void json_encode($model) ); } + + #[Test] + public function testScalarEnumCoercesToInstance(): void + { + $model = Ticket::fromArray(['priority' => 'low', 'labels' => []]); + $this->assertSame(TicketPriority::Low, $model->priority); + } + + #[Test] + public function testListOfEnumCoercesElementsToInstances(): void + { + $model = Ticket::fromArray(['priority' => 'low', 'labels' => ['low', 'high']]); + $this->assertCount(2, $model->labels); + $this->assertSame(TicketPriority::Low, $model->labels[0]); + $this->assertSame(TicketPriority::High, $model->labels[1]); + } + + #[Test] + public function testEnumInstancePassesThrough(): void + { + $model = Ticket::fromArray(['priority' => TicketPriority::High, 'labels' => []]); + $this->assertSame(TicketPriority::High, $model->priority); + } + + #[Test] + public function testInvalidEnumScalarFallsBackToData(): void + { + $model = Ticket::fromArray(['priority' => 'urgent', 'labels' => []]); + $this->assertSame('urgent', $model['priority']); + } + + #[Test] + public function testEnumWireFormatStableAcrossConstruction(): void + { + $fromScalar = Ticket::fromArray(['priority' => 'low', 'labels' => ['high']]); + $fromInstance = Ticket::fromArray(['priority' => TicketPriority::Low, 'labels' => [TicketPriority::High]]); + $this->assertSame(json_encode($fromScalar), json_encode($fromInstance)); + } } From 192de547707b52e2d5f60984af9d2c153bef2060 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:33:27 +0000 Subject: [PATCH 31/48] chore(tests): bump steady to v0.22.1 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 7c58865..9c7c439 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.20.2 -- steady --version + npm exec --package=@stdy/cli@0.22.1 -- steady --version - npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index 4f75ee9..bef4dad 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.2 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.22.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=repeat --validator-form-array-format=repeat --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From 82c146af6213f707f29059eed0d9061aa0555c4b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 02:01:36 +0000 Subject: [PATCH 32/48] fix: revert enum parsing change that lead to unconditional failure --- src/Core/Conversion/EnumOf.php | 20 ++--------- tests/Core/ModelTest.php | 62 ---------------------------------- 2 files changed, 3 insertions(+), 79 deletions(-) diff --git a/src/Core/Conversion/EnumOf.php b/src/Core/Conversion/EnumOf.php index c8ce88b..b44c92c 100644 --- a/src/Core/Conversion/EnumOf.php +++ b/src/Core/Conversion/EnumOf.php @@ -19,12 +19,9 @@ final class EnumOf implements Converter /** * @param list $members - * @param class-string<\BackedEnum>|null $class */ - public function __construct( - private readonly array $members, - private readonly ?string $class = null, - ) { + public function __construct(private readonly array $members) + { $type = 'NULL'; foreach ($this->members as $member) { $type = gettype($member); @@ -36,24 +33,13 @@ public function __construct( public static function fromBackedEnum(string $enum): self { // @phpstan-ignore-next-line argument.type - return self::$cache[$enum] ??= new self( - array_column($enum::cases(), column_key: 'value'), - class: $enum, - ); + return self::$cache[$enum] ??= new self(array_column($enum::cases(), column_key: 'value')); } public function coerce(mixed $value, CoerceState $state): mixed { $this->tally($value, state: $state); - if ($value instanceof \BackedEnum) { - return $value; - } - - if (null !== $this->class && (is_int($value) || is_string($value))) { - return ($this->class)::tryFrom($value) ?? $value; - } - return $value; } diff --git a/tests/Core/ModelTest.php b/tests/Core/ModelTest.php index 995da87..68e6e66 100644 --- a/tests/Core/ModelTest.php +++ b/tests/Core/ModelTest.php @@ -47,30 +47,6 @@ public function __construct( } } -enum TicketPriority: string -{ - case Low = 'low'; - case High = 'high'; -} - -class Ticket implements BaseModel -{ - /** @use SdkModel> */ - use SdkModel; - - #[Required(enum: TicketPriority::class)] - public TicketPriority $priority; - - /** @var list */ - #[Required(list: TicketPriority::class)] - public array $labels; - - public function __construct() - { - $this->initialize(); - } -} - /** * @internal * @@ -165,42 +141,4 @@ public function testSerializeModelWithExplicitNull(): void json_encode($model) ); } - - #[Test] - public function testScalarEnumCoercesToInstance(): void - { - $model = Ticket::fromArray(['priority' => 'low', 'labels' => []]); - $this->assertSame(TicketPriority::Low, $model->priority); - } - - #[Test] - public function testListOfEnumCoercesElementsToInstances(): void - { - $model = Ticket::fromArray(['priority' => 'low', 'labels' => ['low', 'high']]); - $this->assertCount(2, $model->labels); - $this->assertSame(TicketPriority::Low, $model->labels[0]); - $this->assertSame(TicketPriority::High, $model->labels[1]); - } - - #[Test] - public function testEnumInstancePassesThrough(): void - { - $model = Ticket::fromArray(['priority' => TicketPriority::High, 'labels' => []]); - $this->assertSame(TicketPriority::High, $model->priority); - } - - #[Test] - public function testInvalidEnumScalarFallsBackToData(): void - { - $model = Ticket::fromArray(['priority' => 'urgent', 'labels' => []]); - $this->assertSame('urgent', $model['priority']); - } - - #[Test] - public function testEnumWireFormatStableAcrossConstruction(): void - { - $fromScalar = Ticket::fromArray(['priority' => 'low', 'labels' => ['high']]); - $fromInstance = Ticket::fromArray(['priority' => TicketPriority::Low, 'labels' => [TicketPriority::High]]); - $this->assertSame(json_encode($fromScalar), json_encode($fromInstance)); - } } From 91d9d0e7e5e35f90aa52187308f366ceb438080b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 28 Apr 2026 02:07:16 +0000 Subject: [PATCH 33/48] feat: support setting headers via env --- src/Client.php | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/src/Client.php b/src/Client.php index b89e8ab..79777ff 100644 --- a/src/Client.php +++ b/src/Client.php @@ -88,18 +88,31 @@ public function __construct( $requestOptions, ); + /** @var array $headers */ + $headers = [ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'User-Agent' => sprintf('beeperdesktop/PHP %s', VERSION), + 'X-Stainless-Lang' => 'php', + 'X-Stainless-Package-Version' => '0.0.1', + 'X-Stainless-Arch' => Util::machtype(), + 'X-Stainless-OS' => Util::ostype(), + 'X-Stainless-Runtime' => php_sapi_name(), + 'X-Stainless-Runtime-Version' => phpversion(), + ]; + + $customHeadersEnv = Util::getenv('BEEPER_DESKTOP_CUSTOM_HEADERS'); + if (null !== $customHeadersEnv) { + foreach (explode("\n", $customHeadersEnv) as $line) { + $colon = strpos($line, ':'); + if (false !== $colon) { + $headers[trim(substr($line, 0, $colon))] = trim(substr($line, $colon + 1)); + } + } + } + parent::__construct( - headers: [ - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - 'User-Agent' => sprintf('beeperdesktop/PHP %s', VERSION), - 'X-Stainless-Lang' => 'php', - 'X-Stainless-Package-Version' => '0.0.1', - 'X-Stainless-Arch' => Util::machtype(), - 'X-Stainless-OS' => Util::ostype(), - 'X-Stainless-Runtime' => php_sapi_name(), - 'X-Stainless-Runtime-Version' => phpversion(), - ], + headers: $headers, baseUrl: $baseUrl, options: $options ); From ea6c13485c34b1a493161585fbe8943761e85968 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:50:32 +0000 Subject: [PATCH 34/48] Update Desktop API Stainless config and OpenAPI spec --- .github/workflows/release-doctor.yml | 4 +- .stats.yml | 4 +- src/Accounts/Account.php | 48 ++-- src/Accounts/Account/Bridge.php | 14 +- src/Accounts/Account/Bridge/Provider.php | 2 +- src/Chats/ChatCreateParams.php | 205 +++++++++++++++-- .../{Params/UnionMember0 => }/Mode.php | 6 +- src/Chats/ChatCreateParams/Params.php | 31 --- .../ChatCreateParams/Params/UnionMember0.php | 166 -------------- .../ChatCreateParams/Params/UnionMember1.php | 191 ---------------- .../Params/UnionMember1/Mode.php | 13 -- .../Params/UnionMember1/Type.php | 15 -- src/Chats/ChatCreateParams/Type.php | 15 ++ .../{Params/UnionMember0 => }/User.php | 4 +- src/Chats/ChatSearchParams.php | 2 +- .../Reactions/ReactionDeleteParams.php | 2 +- src/Client.php | 26 ++- src/Core/BaseClient.php | 5 + src/CursorNoLimit.php | 212 +++++++++--------- src/CursorSearch.php | 212 +++++++++--------- src/CursorSortKey.php | 113 ---------- src/CursorSortKey/Item.php | 48 ---- src/Messages/MessageSearchParams.php | 2 +- src/ServiceContracts/AssetsContract.php | 2 +- src/ServiceContracts/AssetsRawContract.php | 2 +- src/ServiceContracts/ChatsContract.php | 30 ++- src/ServiceContracts/MessagesContract.php | 6 +- src/ServiceContracts/MessagesRawContract.php | 4 +- src/Services/AssetsRawService.php | 5 +- src/Services/AssetsService.php | 2 +- .../Chats/Messages/ReactionsRawService.php | 2 +- .../Chats/Messages/ReactionsService.php | 2 +- src/Services/ChatsRawService.php | 25 ++- src/Services/ChatsService.php | 49 +++- src/Services/InfoRawService.php | 1 + src/Services/MessagesRawService.php | 8 +- src/Services/MessagesService.php | 8 +- tests/Services/AssetsTest.php | 4 +- tests/Services/ChatsTest.php | 26 ++- tests/Services/MessagesTest.php | 4 +- 40 files changed, 605 insertions(+), 915 deletions(-) rename src/Chats/ChatCreateParams/{Params/UnionMember0 => }/Mode.php (51%) delete mode 100644 src/Chats/ChatCreateParams/Params.php delete mode 100644 src/Chats/ChatCreateParams/Params/UnionMember0.php delete mode 100644 src/Chats/ChatCreateParams/Params/UnionMember1.php delete mode 100644 src/Chats/ChatCreateParams/Params/UnionMember1/Mode.php delete mode 100644 src/Chats/ChatCreateParams/Params/UnionMember1/Type.php create mode 100644 src/Chats/ChatCreateParams/Type.php rename src/Chats/ChatCreateParams/{Params/UnionMember0 => }/User.php (94%) delete mode 100644 src/CursorSortKey.php delete mode 100644 src/CursorSortKey/Item.php diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 098c0d1..b0cac61 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -18,5 +18,5 @@ jobs: run: | bash ./bin/check-release-environment env: - PACKAGIST_USERNAME: ${{ secrets.BEEPER_DESKTOP_PACKAGIST_USERNAME || secrets.PACKAGIST_USERNAME }} - PACKAGIST_SAFE_KEY: ${{ secrets.BEEPER_DESKTOP_PACKAGIST_SAFE_KEY || secrets.PACKAGIST_SAFE_KEY }} + PACKAGIST_USERNAME: ${{ secrets.BEEPER_PACKAGIST_USERNAME || secrets.PACKAGIST_USERNAME }} + PACKAGIST_SAFE_KEY: ${{ secrets.BEEPER_PACKAGIST_SAFE_KEY || secrets.PACKAGIST_SAFE_KEY }} diff --git a/.stats.yml b/.stats.yml index 229f6b5..e925f68 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-611aa7641fbca8cf31d626bf86f9efd3c2b92778e897ebbb25c6ea44185ed1ed.yml -openapi_spec_hash: d6c0a1776048dab04f6c5625c9893c9c -config_hash: 39ed0717b5f415499aaace2468346e1a +openapi_spec_hash: 4840f003552e8b48eb8e689b59a819ef +config_hash: 05ebdec072113f63395372504da98192 diff --git a/src/Accounts/Account.php b/src/Accounts/Account.php index 174a24a..8bb48cd 100644 --- a/src/Accounts/Account.php +++ b/src/Accounts/Account.php @@ -5,6 +5,7 @@ namespace BeeperDesktop\Accounts; use BeeperDesktop\Accounts\Account\Bridge; +use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Attributes\Required; use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Contracts\BaseModel; @@ -19,8 +20,8 @@ * @phpstan-type AccountShape = array{ * accountID: string, * bridge: Bridge|BridgeShape, - * network: string, * user: User|UserShape, + * network?: string|null, * } */ final class Account implements BaseModel @@ -35,39 +36,35 @@ final class Account implements BaseModel public string $accountID; /** - * Bridge metadata for the account. Available from Beeper Desktop v.4.2.719+. + * Bridge metadata for the account. Available in Beeper Desktop v4.2.789+. */ #[Required] public Bridge $bridge; /** - * Human-friendly network name for the account. + * User the account belongs to. */ #[Required] - public string $network; + public User $user; /** - * User the account belongs to. + * Human-friendly network name for the account. Omitted when the network is unknown. */ - #[Required] - public User $user; + #[Optional] + public ?string $network; /** * `new Account()` is missing required properties by the API. * * To enforce required parameters use * ``` - * Account::with(accountID: ..., bridge: ..., network: ..., user: ...) + * Account::with(accountID: ..., bridge: ..., user: ...) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new Account) - * ->withAccountID(...) - * ->withBridge(...) - * ->withNetwork(...) - * ->withUser(...) + * (new Account)->withAccountID(...)->withBridge(...)->withUser(...) * ``` */ public function __construct() @@ -86,16 +83,17 @@ public function __construct() public static function with( string $accountID, Bridge|array $bridge, - string $network, - User|array $user + User|array $user, + ?string $network = null, ): self { $self = new self; $self['accountID'] = $accountID; $self['bridge'] = $bridge; - $self['network'] = $network; $self['user'] = $user; + null !== $network && $self['network'] = $network; + return $self; } @@ -111,7 +109,7 @@ public function withAccountID(string $accountID): self } /** - * Bridge metadata for the account. Available from Beeper Desktop v.4.2.719+. + * Bridge metadata for the account. Available in Beeper Desktop v4.2.789+. * * @param Bridge|BridgeShape $bridge */ @@ -124,25 +122,25 @@ public function withBridge(Bridge|array $bridge): self } /** - * Human-friendly network name for the account. + * User the account belongs to. + * + * @param User|UserShape $user */ - public function withNetwork(string $network): self + public function withUser(User|array $user): self { $self = clone $this; - $self['network'] = $network; + $self['user'] = $user; return $self; } /** - * User the account belongs to. - * - * @param User|UserShape $user + * Human-friendly network name for the account. Omitted when the network is unknown. */ - public function withUser(User|array $user): self + public function withNetwork(string $network): self { $self = clone $this; - $self['user'] = $user; + $self['network'] = $network; return $self; } diff --git a/src/Accounts/Account/Bridge.php b/src/Accounts/Account/Bridge.php index 73b4105..2304404 100644 --- a/src/Accounts/Account/Bridge.php +++ b/src/Accounts/Account/Bridge.php @@ -10,7 +10,7 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** - * Bridge metadata for the account. Available from Beeper Desktop v.4.2.719+. + * Bridge metadata for the account. Available in Beeper Desktop v4.2.789+. * * @phpstan-type BridgeShape = array{ * id: string, provider: Provider|value-of, type: string @@ -22,13 +22,13 @@ final class Bridge implements BaseModel use SdkModel; /** - * Bridge instance identifier. + * Bridge instance identifier. Available in Beeper Desktop v4.2.789+. */ #[Required] public string $id; /** - * Bridge provider for the account. + * Bridge provider for the account. Available in Beeper Desktop v4.2.789+. * * @var value-of $provider */ @@ -36,7 +36,7 @@ final class Bridge implements BaseModel public string $provider; /** - * Bridge type. + * Bridge type. Available in Beeper Desktop v4.2.789+. */ #[Required] public string $type; @@ -82,7 +82,7 @@ public static function with( } /** - * Bridge instance identifier. + * Bridge instance identifier. Available in Beeper Desktop v4.2.789+. */ public function withID(string $id): self { @@ -93,7 +93,7 @@ public function withID(string $id): self } /** - * Bridge provider for the account. + * Bridge provider for the account. Available in Beeper Desktop v4.2.789+. * * @param Provider|value-of $provider */ @@ -106,7 +106,7 @@ public function withProvider(Provider|string $provider): self } /** - * Bridge type. + * Bridge type. Available in Beeper Desktop v4.2.789+. */ public function withType(string $type): self { diff --git a/src/Accounts/Account/Bridge/Provider.php b/src/Accounts/Account/Bridge/Provider.php index 59ca678..fcf152d 100644 --- a/src/Accounts/Account/Bridge/Provider.php +++ b/src/Accounts/Account/Bridge/Provider.php @@ -5,7 +5,7 @@ namespace BeeperDesktop\Accounts\Account\Bridge; /** - * Bridge provider for the account. + * Bridge provider for the account. Available in Beeper Desktop v4.2.789+. */ enum Provider: string { diff --git a/src/Chats/ChatCreateParams.php b/src/Chats/ChatCreateParams.php index 76b39b1..c3ae9eb 100644 --- a/src/Chats/ChatCreateParams.php +++ b/src/Chats/ChatCreateParams.php @@ -4,22 +4,32 @@ namespace BeeperDesktop\Chats; -use BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember0; -use BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember1; +use BeeperDesktop\Chats\ChatCreateParams\Mode; +use BeeperDesktop\Chats\ChatCreateParams\Type; +use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Concerns\SdkParams; use BeeperDesktop\Core\Contracts\BaseModel; /** - * Create a single/group chat (mode='create') or start a direct chat from merged user data (mode='start'). + * Create a direct or group chat with mode="create", or use mode="start" to resolve a contact and open a direct chat. * * @see BeeperDesktop\Services\ChatsService::create() * - * @phpstan-import-type ParamsVariants from \BeeperDesktop\Chats\ChatCreateParams\Params - * @phpstan-import-type ParamsShape from \BeeperDesktop\Chats\ChatCreateParams\Params + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User * - * @phpstan-type ChatCreateParamsShape = array{params?: ParamsShape|null} + * @phpstan-type ChatCreateParamsShape = array{ + * accountID: string, + * allowInvite?: bool|null, + * messageText?: string|null, + * mode?: null|Mode|value-of, + * participantIDs?: list|null, + * title?: string|null, + * type?: null|Type|value-of, + * user?: null|User|UserShape, + * } */ final class ChatCreateParams implements BaseModel { @@ -27,10 +37,74 @@ final class ChatCreateParams implements BaseModel use SdkModel; use SdkParams; - /** @var ParamsVariants|null $params */ + /** + * Account to create or start the chat on. + */ + #[Required] + public string $accountID; + + /** + * Only used for mode='start'. Whether invite-based DM creation is allowed when required by the platform. + */ + #[Optional] + public ?bool $allowInvite; + + /** + * Optional first message content if the platform requires it to create the chat. + */ + #[Optional] + public ?string $messageText; + + /** + * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. Omit or set 'create' to create a chat directly. + * + * @var value-of|null $mode + */ + #[Optional(enum: Mode::class)] + public ?string $mode; + + /** + * Required for create mode. Provide exactly one user ID for 'single' chats and one or more for 'group' chats. + * + * @var list|null $participantIDs + */ + #[Optional(list: 'string')] + public ?array $participantIDs; + + /** + * Optional title for group chats; ignored for single chats on most networks. + */ + #[Optional] + public ?string $title; + + /** + * Required for create mode. 'single' creates a direct message chat; 'group' creates a group chat. + * + * @var value-of|null $type + */ + #[Optional(enum: Type::class)] + public ?string $type; + + /** + * Required for mode='start'. Merged user-like contact payload used to resolve the best identifier. + */ #[Optional] - public UnionMember0|UnionMember1|null $params; + public ?User $user; + /** + * `new ChatCreateParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * ChatCreateParams::with(accountID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new ChatCreateParams)->withAccountID(...) + * ``` + */ public function __construct() { $this->initialize(); @@ -41,25 +115,128 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param ParamsShape|null $params + * @param Mode|value-of|null $mode + * @param list|null $participantIDs + * @param Type|value-of|null $type + * @param User|UserShape|null $user */ public static function with( - UnionMember0|array|UnionMember1|null $params = null + string $accountID, + ?bool $allowInvite = null, + ?string $messageText = null, + Mode|string|null $mode = null, + ?array $participantIDs = null, + ?string $title = null, + Type|string|null $type = null, + User|array|null $user = null, ): self { $self = new self; - null !== $params && $self['params'] = $params; + $self['accountID'] = $accountID; + + null !== $allowInvite && $self['allowInvite'] = $allowInvite; + null !== $messageText && $self['messageText'] = $messageText; + null !== $mode && $self['mode'] = $mode; + null !== $participantIDs && $self['participantIDs'] = $participantIDs; + null !== $title && $self['title'] = $title; + null !== $type && $self['type'] = $type; + null !== $user && $self['user'] = $user; + + return $self; + } + + /** + * Account to create or start the chat on. + */ + public function withAccountID(string $accountID): self + { + $self = clone $this; + $self['accountID'] = $accountID; return $self; } /** - * @param ParamsShape $params + * Only used for mode='start'. Whether invite-based DM creation is allowed when required by the platform. + */ + public function withAllowInvite(bool $allowInvite): self + { + $self = clone $this; + $self['allowInvite'] = $allowInvite; + + return $self; + } + + /** + * Optional first message content if the platform requires it to create the chat. + */ + public function withMessageText(string $messageText): self + { + $self = clone $this; + $self['messageText'] = $messageText; + + return $self; + } + + /** + * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. Omit or set 'create' to create a chat directly. + * + * @param Mode|value-of $mode + */ + public function withMode(Mode|string $mode): self + { + $self = clone $this; + $self['mode'] = $mode; + + return $self; + } + + /** + * Required for create mode. Provide exactly one user ID for 'single' chats and one or more for 'group' chats. + * + * @param list $participantIDs + */ + public function withParticipantIDs(array $participantIDs): self + { + $self = clone $this; + $self['participantIDs'] = $participantIDs; + + return $self; + } + + /** + * Optional title for group chats; ignored for single chats on most networks. + */ + public function withTitle(string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } + + /** + * Required for create mode. 'single' creates a direct message chat; 'group' creates a group chat. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Required for mode='start'. Merged user-like contact payload used to resolve the best identifier. + * + * @param User|UserShape $user */ - public function withParams(UnionMember0|array|UnionMember1 $params): self + public function withUser(User|array $user): self { $self = clone $this; - $self['params'] = $params; + $self['user'] = $user; return $self; } diff --git a/src/Chats/ChatCreateParams/Params/UnionMember0/Mode.php b/src/Chats/ChatCreateParams/Mode.php similarity index 51% rename from src/Chats/ChatCreateParams/Params/UnionMember0/Mode.php rename to src/Chats/ChatCreateParams/Mode.php index 6fd34d7..04f50d3 100644 --- a/src/Chats/ChatCreateParams/Params/UnionMember0/Mode.php +++ b/src/Chats/ChatCreateParams/Mode.php @@ -2,12 +2,14 @@ declare(strict_types=1); -namespace BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember0; +namespace BeeperDesktop\Chats\ChatCreateParams; /** - * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. + * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. Omit or set 'create' to create a chat directly. */ enum Mode: string { case START = 'start'; + + case CREATE = 'create'; } diff --git a/src/Chats/ChatCreateParams/Params.php b/src/Chats/ChatCreateParams/Params.php deleted file mode 100644 index 3a23659..0000000 --- a/src/Chats/ChatCreateParams/Params.php +++ /dev/null @@ -1,31 +0,0 @@ -|array - */ - public static function variants(): array - { - return [UnionMember0::class, UnionMember1::class]; - } -} diff --git a/src/Chats/ChatCreateParams/Params/UnionMember0.php b/src/Chats/ChatCreateParams/Params/UnionMember0.php deleted file mode 100644 index 21194f4..0000000 --- a/src/Chats/ChatCreateParams/Params/UnionMember0.php +++ /dev/null @@ -1,166 +0,0 @@ -, - * user: User|UserShape, - * allowInvite?: bool|null, - * messageText?: string|null, - * } - */ -final class UnionMember0 implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - - /** - * Account to create or start the chat on. - */ - #[Required] - public string $accountID; - - /** - * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. - * - * @var value-of $mode - */ - #[Required(enum: Mode::class)] - public string $mode; - - /** - * Merged user-like contact payload used to resolve the best identifier. - */ - #[Required] - public User $user; - - /** - * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. - */ - #[Optional] - public ?bool $allowInvite; - - /** - * Optional first message content if the platform requires it to create the chat. - */ - #[Optional] - public ?string $messageText; - - /** - * `new UnionMember0()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * UnionMember0::with(accountID: ..., mode: ..., user: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new UnionMember0)->withAccountID(...)->withMode(...)->withUser(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param Mode|value-of $mode - * @param User|UserShape $user - */ - public static function with( - string $accountID, - Mode|string $mode, - User|array $user, - ?bool $allowInvite = null, - ?string $messageText = null, - ): self { - $self = new self; - - $self['accountID'] = $accountID; - $self['mode'] = $mode; - $self['user'] = $user; - - null !== $allowInvite && $self['allowInvite'] = $allowInvite; - null !== $messageText && $self['messageText'] = $messageText; - - return $self; - } - - /** - * Account to create or start the chat on. - */ - public function withAccountID(string $accountID): self - { - $self = clone $this; - $self['accountID'] = $accountID; - - return $self; - } - - /** - * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. - * - * @param Mode|value-of $mode - */ - public function withMode(Mode|string $mode): self - { - $self = clone $this; - $self['mode'] = $mode; - - return $self; - } - - /** - * Merged user-like contact payload used to resolve the best identifier. - * - * @param User|UserShape $user - */ - public function withUser(User|array $user): self - { - $self = clone $this; - $self['user'] = $user; - - return $self; - } - - /** - * Whether invite-based DM creation is allowed when required by the platform. Used for mode='start'. - */ - public function withAllowInvite(bool $allowInvite): self - { - $self = clone $this; - $self['allowInvite'] = $allowInvite; - - return $self; - } - - /** - * Optional first message content if the platform requires it to create the chat. - */ - public function withMessageText(string $messageText): self - { - $self = clone $this; - $self['messageText'] = $messageText; - - return $self; - } -} diff --git a/src/Chats/ChatCreateParams/Params/UnionMember1.php b/src/Chats/ChatCreateParams/Params/UnionMember1.php deleted file mode 100644 index 2f510cb..0000000 --- a/src/Chats/ChatCreateParams/Params/UnionMember1.php +++ /dev/null @@ -1,191 +0,0 @@ -, - * type: Type|value-of, - * messageText?: string|null, - * mode?: null|Mode|value-of, - * title?: string|null, - * } - */ -final class UnionMember1 implements BaseModel -{ - /** @use SdkModel */ - use SdkModel; - - /** - * Account to create or start the chat on. - */ - #[Required] - public string $accountID; - - /** - * User IDs to include in the new chat. - * - * @var list $participantIDs - */ - #[Required(list: 'string')] - public array $participantIDs; - - /** - * 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. - * - * @var value-of $type - */ - #[Required(enum: Type::class)] - public string $type; - - /** - * Optional first message content if the platform requires it to create the chat. - */ - #[Optional] - public ?string $messageText; - - /** - * Operation mode. Defaults to 'create' when omitted. - * - * @var value-of|null $mode - */ - #[Optional(enum: Mode::class)] - public ?string $mode; - - /** - * Optional title for group chats; ignored for single chats on most platforms. - */ - #[Optional] - public ?string $title; - - /** - * `new UnionMember1()` is missing required properties by the API. - * - * To enforce required parameters use - * ``` - * UnionMember1::with(accountID: ..., participantIDs: ..., type: ...) - * ``` - * - * Otherwise ensure the following setters are called - * - * ``` - * (new UnionMember1)->withAccountID(...)->withParticipantIDs(...)->withType(...) - * ``` - */ - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - * - * @param list $participantIDs - * @param Type|value-of $type - * @param Mode|value-of|null $mode - */ - public static function with( - string $accountID, - array $participantIDs, - Type|string $type, - ?string $messageText = null, - Mode|string|null $mode = null, - ?string $title = null, - ): self { - $self = new self; - - $self['accountID'] = $accountID; - $self['participantIDs'] = $participantIDs; - $self['type'] = $type; - - null !== $messageText && $self['messageText'] = $messageText; - null !== $mode && $self['mode'] = $mode; - null !== $title && $self['title'] = $title; - - return $self; - } - - /** - * Account to create or start the chat on. - */ - public function withAccountID(string $accountID): self - { - $self = clone $this; - $self['accountID'] = $accountID; - - return $self; - } - - /** - * User IDs to include in the new chat. - * - * @param list $participantIDs - */ - public function withParticipantIDs(array $participantIDs): self - { - $self = clone $this; - $self['participantIDs'] = $participantIDs; - - return $self; - } - - /** - * 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. - * - * @param Type|value-of $type - */ - public function withType(Type|string $type): self - { - $self = clone $this; - $self['type'] = $type; - - return $self; - } - - /** - * Optional first message content if the platform requires it to create the chat. - */ - public function withMessageText(string $messageText): self - { - $self = clone $this; - $self['messageText'] = $messageText; - - return $self; - } - - /** - * Operation mode. Defaults to 'create' when omitted. - * - * @param Mode|value-of $mode - */ - public function withMode(Mode|string $mode): self - { - $self = clone $this; - $self['mode'] = $mode; - - return $self; - } - - /** - * Optional title for group chats; ignored for single chats on most platforms. - */ - public function withTitle(string $title): self - { - $self = clone $this; - $self['title'] = $title; - - return $self; - } -} diff --git a/src/Chats/ChatCreateParams/Params/UnionMember1/Mode.php b/src/Chats/ChatCreateParams/Params/UnionMember1/Mode.php deleted file mode 100644 index bd342be..0000000 --- a/src/Chats/ChatCreateParams/Params/UnionMember1/Mode.php +++ /dev/null @@ -1,13 +0,0 @@ - phpversion(), ]; - $customHeadersEnv = Util::getenv('BEEPER_DESKTOP_CUSTOM_HEADERS'); + $customHeadersEnv = Util::getenv('BEEPER_CUSTOM_HEADERS'); if (null !== $customHeadersEnv) { foreach (explode("\n", $customHeadersEnv) as $line) { $colon = strpos($line, ':'); @@ -172,8 +170,18 @@ public function search( return $this->beeperDesktopClientService->search($query, $requestOptions); } + /** + * @param array{bearerAuth?: bool} $security + * + * @return array + */ + protected function authHeaders(array $security): array + { + return [...($security['bearerAuth'] ?? false) ? $this->bearerAuth() : []]; + } + /** @return array */ - protected function authHeaders(): array + protected function bearerAuth(): array { return $this->accessToken ? [ 'Authorization' => "Bearer {$this->accessToken}", @@ -187,6 +195,7 @@ protected function authHeaders(): array * @param array $query * @param array|null> $headers * @param RequestOpts|null $opts + * @param array{bearerAuth?: bool}|null $security * * @return array{NormalizedRequest, RequestOptions} */ @@ -197,14 +206,19 @@ protected function buildRequest( array $headers, mixed $body, RequestOptions|array|null $opts, + ?array $security = null, ): array { return parent::buildRequest( method: $method, path: $path, query: $query, - headers: [...$this->authHeaders(), ...$headers], + headers: [ + ...$this->authHeaders(security: ($security ?? ['bearerAuth' => true])), + ...$headers, + ], body: $body, opts: $opts, + security: $security, ); } } diff --git a/src/Core/BaseClient.php b/src/Core/BaseClient.php index 14b35ea..bed6a0d 100644 --- a/src/Core/BaseClient.php +++ b/src/Core/BaseClient.php @@ -55,6 +55,7 @@ public function __construct( * @param string|int|list|null $unwrap * @param class-string>|null $page * @param class-string>|null $stream + * @param array{bearerAuth?: bool}|null $security * @param RequestOptions|array|null $options * * @return BaseResponse @@ -69,6 +70,7 @@ public function request( string|Converter|ConverterSource|null $convert = null, ?string $page = null, ?string $stream = null, + ?array $security = null, RequestOptions|array|null $options = [], ): BaseResponse { [$req, $opts] = $this->buildRequest( @@ -79,6 +81,7 @@ public function request( // @phpstan-ignore argument.type headers: $headers, body: $body, + security: $security, // @phpstan-ignore argument.type opts: $options, ); @@ -113,6 +116,7 @@ protected function generateIdempotencyKey(): string * @param array $query * @param array|null> $headers * @param RequestOpts|null $opts + * @param array{bearerAuth?: bool}|null $security * * @return array{NormalizedRequest, RequestOptions} */ @@ -123,6 +127,7 @@ protected function buildRequest( array $headers, mixed $body, RequestOptions|array|null $opts, + ?array $security = null, ): array { $options = RequestOptions::parse($this->options, $opts); diff --git a/src/CursorNoLimit.php b/src/CursorNoLimit.php index 5ea1b0c..9398fb2 100644 --- a/src/CursorNoLimit.php +++ b/src/CursorNoLimit.php @@ -2,132 +2,122 @@ namespace BeeperDesktop; -use BeeperDesktop\Core\Conversion; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Concerns\SdkPage; use BeeperDesktop\Core\Contracts\BaseModel; use BeeperDesktop\Core\Contracts\BasePage; -use BeeperDesktop\Core\Conversion\ListOf; +use BeeperDesktop\Core\Conversion; use BeeperDesktop\Core\Conversion\Contracts\Converter; use BeeperDesktop\Core\Conversion\Contracts\ConverterSource; +use BeeperDesktop\Core\Conversion\ListOf; use Psr\Http\Message\ResponseInterface; /** - * - * @phpstan-type CursorNoLimitShape = array{ - * items?: list>|null, - * hasMore?: bool|null, - * oldestCursor?: string|null, - * newestCursor?: string|null, - * } - * @template TItem - * @implements BasePage - * + * @phpstan-type CursorNoLimitShape = array{ + * items?: list>|null, + * hasMore?: bool|null, + * oldestCursor?: string|null, + * newestCursor?: string|null, + * } + * + * @template TItem + * + * @implements BasePage */ final class CursorNoLimit implements BaseModel, BasePage { - /** @use SdkModel */ - use SdkModel; - - /** @use SdkPage */ - use SdkPage; - - /** @var list|null $items */ - #[Optional(list: 'mixed')] - public ?array $items; - - /** @var bool|null $hasMore */ - #[Optional] - public ?bool $hasMore; - - /** @var string|null $oldestCursor */ - #[Optional(nullable: true)] - public ?string $oldestCursor; - - /** @var string|null $newestCursor */ - #[Optional(nullable: true)] - public ?string $newestCursor; - - /** @return list */ - function getItems(): array { - // @phpstan-ignore-next-line return.type - return $this->offsetGet('items') ?? []; - } - - /** - * @internal - * - * @return array{ - * array{ - * method: string, - * path: string, - * query: array, - * headers: array>, - * body: mixed, - * }, - * RequestOptions, - * }|null - */ - function nextRequest(): ?array { - if (!($this->hasMore ?? null)||!count($this->getItems())) { - return null; - + /** @use SdkModel */ + use SdkModel; + + /** @use SdkPage */ + use SdkPage; + + /** @var list|null $items */ + #[Optional(list: 'mixed')] + public ?array $items; + + #[Optional] + public ?bool $hasMore; + + #[Optional(nullable: true)] + public ?string $oldestCursor; + + #[Optional(nullable: true)] + public ?string $newestCursor; + + /** + * @internal + * + * @param array{ + * method: string, + * path: string, + * query: array, + * headers: array|null>, + * body: mixed, + * } $requestInfo + */ + public function __construct( + private string|Converter|ConverterSource $convert, + private Client $client, + private array $requestInfo, + private RequestOptions $options, + private ResponseInterface $response, + private mixed $parsedBody, + ) { + $this->initialize(); + + if (!is_array($this->parsedBody)) { + return; + } + + // @phpstan-ignore-next-line argument.type + self::__unserialize($this->parsedBody); + + if (is_array($items = $this->offsetGet('items'))) { + $parsed = Conversion::coerce(new ListOf($convert), value: $items); + // @phpstan-ignore-next-line + $this->offsetSet('items', value: $parsed); + } } - if (!($prev = $this->newestCursor ?? null)&&!($next = $this - ->oldestCursor ?? null)) { - return null; - + /** @return list */ + public function getItems(): array + { + // @phpstan-ignore-next-line return.type + return $this->offsetGet('items') ?? []; } - $nextRequest = array_merge_recursive( - $this->requestInfo, - ['query' => empty($prev) ? ['cursor' => $next] : [=> $prev]], - ); - - // @phpstan-ignore-next-line return.type - return [$nextRequest, $this->options]; - } - - /** - * @internal - * - * @param string|Converter|ConverterSource $convert - * @param Client $client - * @param array{ - * method: string, - * path: string, - * query: array, - * headers: array>, - * body: mixed, - * } $requestInfo - * @param RequestOptions $options - * @param mixed $parsedBody - */ - function __construct( - private string|Converter|ConverterSource $convert, - private Client $client, - private array $requestInfo, - private RequestOptions $options, - private ResponseInterface $response, - private mixed $parsedBody, - ) { - $this->initialize(); - - if (!is_array($this->parsedBody)) { - return; - - } - - // @phpstan-ignore-next-line argument.type - self::__unserialize($this->parsedBody); - - if (is_array($items = $this->offsetGet('items'))) { - $parsed = Conversion::coerce(new ListOf($convert), value: $items); - // @phpstan-ignore-next-line - $this->offsetSet('items', value: $parsed); - + /** + * @internal + * + * @return array{ + * array{ + * method: string, + * path: string, + * query: array, + * headers: array|null>, + * body: mixed, + * }, + * RequestOptions, + * }|null + */ + public function nextRequest(): ?array + { + if (!($this->hasMore ?? null) || !count($this->getItems())) { + return null; + } + + if (!($next = $this->oldestCursor ?? null)) { + return null; + } + + $nextRequest = array_merge_recursive( + $this->requestInfo, + ['query' => ['cursor' => $next]] + ); + + // @phpstan-ignore-next-line return.type + return [$nextRequest, $this->options]; } - } -} \ No newline at end of file +} diff --git a/src/CursorSearch.php b/src/CursorSearch.php index 9d46758..248cae5 100644 --- a/src/CursorSearch.php +++ b/src/CursorSearch.php @@ -2,132 +2,122 @@ namespace BeeperDesktop; -use BeeperDesktop\Core\Conversion; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Concerns\SdkPage; use BeeperDesktop\Core\Contracts\BaseModel; use BeeperDesktop\Core\Contracts\BasePage; -use BeeperDesktop\Core\Conversion\ListOf; +use BeeperDesktop\Core\Conversion; use BeeperDesktop\Core\Conversion\Contracts\Converter; use BeeperDesktop\Core\Conversion\Contracts\ConverterSource; +use BeeperDesktop\Core\Conversion\ListOf; use Psr\Http\Message\ResponseInterface; /** - * - * @phpstan-type CursorSearchShape = array{ - * items?: list>|null, - * hasMore?: bool|null, - * oldestCursor?: string|null, - * newestCursor?: string|null, - * } - * @template TItem - * @implements BasePage - * + * @phpstan-type CursorSearchShape = array{ + * items?: list>|null, + * hasMore?: bool|null, + * oldestCursor?: string|null, + * newestCursor?: string|null, + * } + * + * @template TItem + * + * @implements BasePage */ final class CursorSearch implements BaseModel, BasePage { - /** @use SdkModel */ - use SdkModel; - - /** @use SdkPage */ - use SdkPage; - - /** @var list|null $items */ - #[Optional(list: 'mixed')] - public ?array $items; - - /** @var bool|null $hasMore */ - #[Optional] - public ?bool $hasMore; - - /** @var string|null $oldestCursor */ - #[Optional(nullable: true)] - public ?string $oldestCursor; - - /** @var string|null $newestCursor */ - #[Optional(nullable: true)] - public ?string $newestCursor; - - /** @return list */ - function getItems(): array { - // @phpstan-ignore-next-line return.type - return $this->offsetGet('items') ?? []; - } - - /** - * @internal - * - * @return array{ - * array{ - * method: string, - * path: string, - * query: array, - * headers: array>, - * body: mixed, - * }, - * RequestOptions, - * }|null - */ - function nextRequest(): ?array { - if (!($this->hasMore ?? null)||!count($this->getItems())) { - return null; - + /** @use SdkModel */ + use SdkModel; + + /** @use SdkPage */ + use SdkPage; + + /** @var list|null $items */ + #[Optional(list: 'mixed')] + public ?array $items; + + #[Optional] + public ?bool $hasMore; + + #[Optional(nullable: true)] + public ?string $oldestCursor; + + #[Optional(nullable: true)] + public ?string $newestCursor; + + /** + * @internal + * + * @param array{ + * method: string, + * path: string, + * query: array, + * headers: array|null>, + * body: mixed, + * } $requestInfo + */ + public function __construct( + private string|Converter|ConverterSource $convert, + private Client $client, + private array $requestInfo, + private RequestOptions $options, + private ResponseInterface $response, + private mixed $parsedBody, + ) { + $this->initialize(); + + if (!is_array($this->parsedBody)) { + return; + } + + // @phpstan-ignore-next-line argument.type + self::__unserialize($this->parsedBody); + + if (is_array($items = $this->offsetGet('items'))) { + $parsed = Conversion::coerce(new ListOf($convert), value: $items); + // @phpstan-ignore-next-line + $this->offsetSet('items', value: $parsed); + } } - if (!($prev = $this->newestCursor ?? null)&&!($next = $this - ->oldestCursor ?? null)) { - return null; - + /** @return list */ + public function getItems(): array + { + // @phpstan-ignore-next-line return.type + return $this->offsetGet('items') ?? []; } - $nextRequest = array_merge_recursive( - $this->requestInfo, - ['query' => empty($prev) ? ['cursor' => $next] : [=> $prev]], - ); - - // @phpstan-ignore-next-line return.type - return [$nextRequest, $this->options]; - } - - /** - * @internal - * - * @param string|Converter|ConverterSource $convert - * @param Client $client - * @param array{ - * method: string, - * path: string, - * query: array, - * headers: array>, - * body: mixed, - * } $requestInfo - * @param RequestOptions $options - * @param mixed $parsedBody - */ - function __construct( - private string|Converter|ConverterSource $convert, - private Client $client, - private array $requestInfo, - private RequestOptions $options, - private ResponseInterface $response, - private mixed $parsedBody, - ) { - $this->initialize(); - - if (!is_array($this->parsedBody)) { - return; - - } - - // @phpstan-ignore-next-line argument.type - self::__unserialize($this->parsedBody); - - if (is_array($items = $this->offsetGet('items'))) { - $parsed = Conversion::coerce(new ListOf($convert), value: $items); - // @phpstan-ignore-next-line - $this->offsetSet('items', value: $parsed); - + /** + * @internal + * + * @return array{ + * array{ + * method: string, + * path: string, + * query: array, + * headers: array|null>, + * body: mixed, + * }, + * RequestOptions, + * }|null + */ + public function nextRequest(): ?array + { + if (!($this->hasMore ?? null) || !count($this->getItems())) { + return null; + } + + if (!($next = $this->oldestCursor ?? null)) { + return null; + } + + $nextRequest = array_merge_recursive( + $this->requestInfo, + ['query' => ['cursor' => $next]] + ); + + // @phpstan-ignore-next-line return.type + return [$nextRequest, $this->options]; } - } -} \ No newline at end of file +} diff --git a/src/CursorSortKey.php b/src/CursorSortKey.php deleted file mode 100644 index 7cdfa0c..0000000 --- a/src/CursorSortKey.php +++ /dev/null @@ -1,113 +0,0 @@ -|null, hasMore?: bool|null - * } - * - * @template TItem - * - * @implements BasePage - */ -final class CursorSortKey implements BaseModel, BasePage -{ - /** @use SdkModel */ - use SdkModel; - - /** @use SdkPage */ - use SdkPage; - - /** @var list|null $items */ - #[Optional(list: 'mixed')] - public ?array $items; - - #[Optional] - public ?bool $hasMore; - - /** - * @internal - * - * @param array{ - * method: string, - * path: string, - * query: array, - * headers: array|null>, - * body: mixed, - * } $requestInfo - */ - public function __construct( - private string|Converter|ConverterSource $convert, - private Client $client, - private array $requestInfo, - private RequestOptions $options, - private ResponseInterface $response, - private mixed $parsedBody, - ) { - $this->initialize(); - - if (!is_array($this->parsedBody)) { - return; - } - - // @phpstan-ignore-next-line argument.type - self::__unserialize($this->parsedBody); - - if (is_array($items = $this->offsetGet('items'))) { - $parsed = Conversion::coerce(new ListOf($convert), value: $items); - // @phpstan-ignore-next-line - $this->offsetSet('items', value: $parsed); - } - } - - /** @return list */ - public function getItems(): array - { - // @phpstan-ignore-next-line return.type - return $this->offsetGet('items') ?? []; - } - - /** - * @internal - * - * @return array{ - * array{ - * method: string, - * path: string, - * query: array, - * headers: array|null>, - * body: mixed, - * }, - * RequestOptions, - * }|null - */ - public function nextRequest(): ?array - { - $items = $this->getItems(); - if (!($this - ->hasMore ?? null) || !count($items) || !($key = array_key_last($items))) { - return null; - } - - $nextRequest = array_merge_recursive( - $this->requestInfo, - ['query' => ['sortKey' => $items[$key]]] - ); - - // @phpstan-ignore-next-line return.type - return [$nextRequest, $this->options]; - } -} diff --git a/src/CursorSortKey/Item.php b/src/CursorSortKey/Item.php deleted file mode 100644 index f3fe595..0000000 --- a/src/CursorSortKey/Item.php +++ /dev/null @@ -1,48 +0,0 @@ - */ - use SdkModel; - - #[Optional] - public ?string $sortKey; - - public function __construct() - { - $this->initialize(); - } - - /** - * Construct an instance from the required parameters. - * - * You must use named parameters to construct any parameters with a default value. - */ - public static function with(?string $sortKey = null): self - { - $self = new self; - - null !== $sortKey && $self['sortKey'] = $sortKey; - - return $self; - } - - public function withSortKey(string $sortKey): self - { - $self = clone $this; - $self['sortKey'] = $sortKey; - - return $self; - } -} diff --git a/src/Messages/MessageSearchParams.php b/src/Messages/MessageSearchParams.php index 49d617f..706245f 100644 --- a/src/Messages/MessageSearchParams.php +++ b/src/Messages/MessageSearchParams.php @@ -13,7 +13,7 @@ use BeeperDesktop\Messages\MessageSearchParams\MediaType; /** - * Search messages across chats using Beeper's message index. + * Search messages across chats. * * @see BeeperDesktop\Services\MessagesService::search() * diff --git a/src/ServiceContracts/AssetsContract.php b/src/ServiceContracts/AssetsContract.php index dff92bd..029710d 100644 --- a/src/ServiceContracts/AssetsContract.php +++ b/src/ServiceContracts/AssetsContract.php @@ -40,7 +40,7 @@ public function download( public function serve( string $url, RequestOptions|array|null $requestOptions = null - ): mixed; + ): string; /** * @api diff --git a/src/ServiceContracts/AssetsRawContract.php b/src/ServiceContracts/AssetsRawContract.php index 2e7e75d..b438606 100644 --- a/src/ServiceContracts/AssetsRawContract.php +++ b/src/ServiceContracts/AssetsRawContract.php @@ -41,7 +41,7 @@ public function download( * @param array|AssetServeParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse + * @return BaseResponse * * @throws APIException */ diff --git a/src/ServiceContracts/ChatsContract.php b/src/ServiceContracts/ChatsContract.php index 06b2871..55837ea 100644 --- a/src/ServiceContracts/ChatsContract.php +++ b/src/ServiceContracts/ChatsContract.php @@ -5,21 +5,21 @@ namespace BeeperDesktop\ServiceContracts; use BeeperDesktop\Chats\Chat; -use BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember0; -use BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember1; +use BeeperDesktop\Chats\ChatCreateParams\Mode; +use BeeperDesktop\Chats\ChatCreateParams\Type; +use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; use BeeperDesktop\Chats\ChatNewResponse; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; -use BeeperDesktop\Chats\ChatSearchParams\Type; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; use BeeperDesktop\RequestOptions; /** - * @phpstan-import-type ParamsShape from \BeeperDesktop\Chats\ChatCreateParams\Params + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ interface ChatsContract @@ -27,13 +27,27 @@ interface ChatsContract /** * @api * - * @param ParamsShape $params + * @param string $accountID account to create or start the chat on + * @param bool $allowInvite Only used for mode='start'. Whether invite-based DM creation is allowed when required by the platform. + * @param string $messageText optional first message content if the platform requires it to create the chat + * @param Mode|value-of $mode Operation mode. Use 'start' to resolve a user/contact and start a direct chat. Omit or set 'create' to create a chat directly. + * @param list $participantIDs Required for create mode. Provide exactly one user ID for 'single' chats and one or more for 'group' chats. + * @param string $title optional title for group chats; ignored for single chats on most networks + * @param Type|value-of $type Required for create mode. 'single' creates a direct message chat; 'group' creates a group chat. + * @param User|UserShape $user Required for mode='start'. Merged user-like contact payload used to resolve the best identifier. * @param RequestOpts|null $requestOptions * * @throws APIException */ public function create( - UnionMember0|array|UnionMember1|null $params = null, + string $accountID, + bool $allowInvite = true, + ?string $messageText = null, + Mode|string|null $mode = null, + ?array $participantIDs = null, + ?string $title = null, + Type|string|null $type = null, + User|array|null $user = null, RequestOptions|array|null $requestOptions = null, ): ChatNewResponse; @@ -99,7 +113,7 @@ public function archive( * @param int $limit Set the maximum number of chats to retrieve. Valid range: 1-200, default is 50 * @param string $query Literal token search (non-semantic). Use single words users type (e.g., "dinner"). When multiple words provided, ALL must match. Case-insensitive. * @param Scope|value-of $scope search scope: 'titles' matches title + network; 'participants' matches participant names - * @param Type|value-of $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types + * @param \BeeperDesktop\Chats\ChatSearchParams\Type|value-of<\BeeperDesktop\Chats\ChatSearchParams\Type> $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types * @param bool|null $unreadOnly Set to true to only retrieve chats that have unread messages * @param RequestOpts|null $requestOptions * @@ -118,7 +132,7 @@ public function search( int $limit = 50, ?string $query = null, Scope|string $scope = 'titles', - Type|string $type = 'any', + \BeeperDesktop\Chats\ChatSearchParams\Type|string $type = 'any', ?bool $unreadOnly = null, RequestOptions|array|null $requestOptions = null, ): CursorSearch; diff --git a/src/ServiceContracts/MessagesContract.php b/src/ServiceContracts/MessagesContract.php index e8c3a3e..66c79a4 100644 --- a/src/ServiceContracts/MessagesContract.php +++ b/src/ServiceContracts/MessagesContract.php @@ -5,8 +5,8 @@ namespace BeeperDesktop\ServiceContracts; use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; -use BeeperDesktop\CursorSortKey; use BeeperDesktop\Message; use BeeperDesktop\Messages\MessageListParams\Direction; use BeeperDesktop\Messages\MessageSearchParams\ChatType; @@ -47,7 +47,7 @@ public function update( * @param Direction|value-of $direction Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided. * @param RequestOpts|null $requestOptions * - * @return CursorSortKey + * @return CursorNoLimit * * @throws APIException */ @@ -56,7 +56,7 @@ public function list( ?string $cursor = null, Direction|string|null $direction = null, RequestOptions|array|null $requestOptions = null, - ): CursorSortKey; + ): CursorNoLimit; /** * @api diff --git a/src/ServiceContracts/MessagesRawContract.php b/src/ServiceContracts/MessagesRawContract.php index 0afdc79..7a1c531 100644 --- a/src/ServiceContracts/MessagesRawContract.php +++ b/src/ServiceContracts/MessagesRawContract.php @@ -6,8 +6,8 @@ use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; -use BeeperDesktop\CursorSortKey; use BeeperDesktop\Message; use BeeperDesktop\Messages\MessageListParams; use BeeperDesktop\Messages\MessageSearchParams; @@ -46,7 +46,7 @@ public function update( * @param array|MessageListParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse> + * @return BaseResponse> * * @throws APIException */ diff --git a/src/Services/AssetsRawService.php b/src/Services/AssetsRawService.php index 22d415c..94db5e4 100644 --- a/src/Services/AssetsRawService.php +++ b/src/Services/AssetsRawService.php @@ -70,7 +70,7 @@ public function download( * @param array{url: string}|AssetServeParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse + * @return BaseResponse * * @throws APIException */ @@ -88,8 +88,9 @@ public function serve( method: 'get', path: 'v1/assets/serve', query: $parsed, + headers: ['Accept' => 'application/octet-stream'], options: $options, - convert: null, + convert: 'string', ); } diff --git a/src/Services/AssetsService.php b/src/Services/AssetsService.php index 4027449..95dfa91 100644 --- a/src/Services/AssetsService.php +++ b/src/Services/AssetsService.php @@ -69,7 +69,7 @@ public function download( public function serve( string $url, RequestOptions|array|null $requestOptions = null - ): mixed { + ): string { $params = Util::removeNulls(['url' => $url]); // @phpstan-ignore-next-line argument.type diff --git a/src/Services/Chats/Messages/ReactionsRawService.php b/src/Services/Chats/Messages/ReactionsRawService.php index 80a8750..dcfb515 100644 --- a/src/Services/Chats/Messages/ReactionsRawService.php +++ b/src/Services/Chats/Messages/ReactionsRawService.php @@ -30,7 +30,7 @@ public function __construct(private Client $client) {} /** * @api * - * Remove the authenticated user's reaction from an existing message. + * Remove the reaction added by the authenticated user from an existing message. * * @param string $messageID Path param: ID of the message to remove a reaction from * @param array{chatID: string, reactionKey: string}|ReactionDeleteParams $params diff --git a/src/Services/Chats/Messages/ReactionsService.php b/src/Services/Chats/Messages/ReactionsService.php index 83d410b..06fd937 100644 --- a/src/Services/Chats/Messages/ReactionsService.php +++ b/src/Services/Chats/Messages/ReactionsService.php @@ -35,7 +35,7 @@ public function __construct(private Client $client) /** * @api * - * Remove the authenticated user's reaction from an existing message. + * Remove the reaction added by the authenticated user from an existing message. * * @param string $messageID Path param: ID of the message to remove a reaction from * @param string $chatID path param: Unique identifier of the chat diff --git a/src/Services/ChatsRawService.php b/src/Services/ChatsRawService.php index 34751aa..3140e67 100644 --- a/src/Services/ChatsRawService.php +++ b/src/Services/ChatsRawService.php @@ -7,6 +7,9 @@ use BeeperDesktop\Chats\Chat; use BeeperDesktop\Chats\ChatArchiveParams; use BeeperDesktop\Chats\ChatCreateParams; +use BeeperDesktop\Chats\ChatCreateParams\Mode; +use BeeperDesktop\Chats\ChatCreateParams\Type; +use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Chats\ChatListParams; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; @@ -15,7 +18,6 @@ use BeeperDesktop\Chats\ChatSearchParams; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; -use BeeperDesktop\Chats\ChatSearchParams\Type; use BeeperDesktop\Client; use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; @@ -27,7 +29,7 @@ /** * Manage chats. * - * @phpstan-import-type ParamsShape from \BeeperDesktop\Chats\ChatCreateParams\Params + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class ChatsRawService implements ChatsRawContract @@ -41,9 +43,18 @@ public function __construct(private Client $client) {} /** * @api * - * Create a single/group chat (mode='create') or start a direct chat from merged user data (mode='start'). + * Create a direct or group chat with mode="create", or use mode="start" to resolve a contact and open a direct chat. * - * @param array{params?: ParamsShape}|ChatCreateParams $params + * @param array{ + * accountID: string, + * allowInvite?: bool, + * messageText?: string, + * mode?: Mode|value-of, + * participantIDs?: list, + * title?: string, + * type?: Type|value-of, + * user?: User|UserShape, + * }|ChatCreateParams $params * @param RequestOpts|null $requestOptions * * @return BaseResponse @@ -63,7 +74,7 @@ public function create( return $this->client->request( method: 'post', path: 'v1/chats', - body: (object) $parsed['params'], + body: (object) $parsed, options: $options, convert: ChatNewResponse::class, ); @@ -174,7 +185,7 @@ public function archive( /** * @api * - * Search chats by title/network or participants using Beeper Desktop's renderer algorithm. + * Search chats by title, network, or participant names. * * @param array{ * accountIDs?: list, @@ -187,7 +198,7 @@ public function archive( * limit?: int, * query?: string, * scope?: Scope|value-of, - * type?: Type|value-of, + * type?: ChatSearchParams\Type|value-of, * unreadOnly?: bool|null, * }|ChatSearchParams $params * @param RequestOpts|null $requestOptions diff --git a/src/Services/ChatsService.php b/src/Services/ChatsService.php index b103c76..9f7169e 100644 --- a/src/Services/ChatsService.php +++ b/src/Services/ChatsService.php @@ -5,14 +5,14 @@ namespace BeeperDesktop\Services; use BeeperDesktop\Chats\Chat; -use BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember0; -use BeeperDesktop\Chats\ChatCreateParams\Params\UnionMember1; +use BeeperDesktop\Chats\ChatCreateParams\Mode; +use BeeperDesktop\Chats\ChatCreateParams\Type; +use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; use BeeperDesktop\Chats\ChatNewResponse; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; -use BeeperDesktop\Chats\ChatSearchParams\Type; use BeeperDesktop\Client; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\Core\Util; @@ -26,7 +26,7 @@ /** * Manage chats. * - * @phpstan-import-type ParamsShape from \BeeperDesktop\Chats\ChatCreateParams\Params + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class ChatsService implements ChatsContract @@ -59,21 +59,46 @@ public function __construct(private Client $client) /** * @api * - * Create a single/group chat (mode='create') or start a direct chat from merged user data (mode='start'). + * Create a direct or group chat with mode="create", or use mode="start" to resolve a contact and open a direct chat. * - * @param ParamsShape $params + * @param string $accountID account to create or start the chat on + * @param bool $allowInvite Only used for mode='start'. Whether invite-based DM creation is allowed when required by the platform. + * @param string $messageText optional first message content if the platform requires it to create the chat + * @param Mode|value-of $mode Operation mode. Use 'start' to resolve a user/contact and start a direct chat. Omit or set 'create' to create a chat directly. + * @param list $participantIDs Required for create mode. Provide exactly one user ID for 'single' chats and one or more for 'group' chats. + * @param string $title optional title for group chats; ignored for single chats on most networks + * @param Type|value-of $type Required for create mode. 'single' creates a direct message chat; 'group' creates a group chat. + * @param User|UserShape $user Required for mode='start'. Merged user-like contact payload used to resolve the best identifier. * @param RequestOpts|null $requestOptions * * @throws APIException */ public function create( - UnionMember0|array|UnionMember1|null $params = null, + string $accountID, + bool $allowInvite = true, + ?string $messageText = null, + Mode|string|null $mode = null, + ?array $participantIDs = null, + ?string $title = null, + Type|string|null $type = null, + User|array|null $user = null, RequestOptions|array|null $requestOptions = null, ): ChatNewResponse { - $params1 = Util::removeNulls(['params' => $params]); + $params = Util::removeNulls( + [ + 'accountID' => $accountID, + 'allowInvite' => $allowInvite, + 'messageText' => $messageText, + 'mode' => $mode, + 'participantIDs' => $participantIDs, + 'title' => $title, + 'type' => $type, + 'user' => $user, + ], + ); // @phpstan-ignore-next-line argument.type - $response = $this->raw->create(params: $params1, requestOptions: $requestOptions); + $response = $this->raw->create(params: $params, requestOptions: $requestOptions); return $response->parse(); } @@ -165,7 +190,7 @@ public function archive( /** * @api * - * Search chats by title/network or participants using Beeper Desktop's renderer algorithm. + * Search chats by title, network, or participant names. * * @param list $accountIDs Provide an array of account IDs to filter chats from specific messaging accounts only * @param string $cursor Opaque pagination cursor; do not inspect. Use together with 'direction'. @@ -177,7 +202,7 @@ public function archive( * @param int $limit Set the maximum number of chats to retrieve. Valid range: 1-200, default is 50 * @param string $query Literal token search (non-semantic). Use single words users type (e.g., "dinner"). When multiple words provided, ALL must match. Case-insensitive. * @param Scope|value-of $scope search scope: 'titles' matches title + network; 'participants' matches participant names - * @param Type|value-of $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types + * @param \BeeperDesktop\Chats\ChatSearchParams\Type|value-of<\BeeperDesktop\Chats\ChatSearchParams\Type> $type Specify the type of chats to retrieve: use "single" for direct messages, "group" for group chats, or "any" to get all types * @param bool|null $unreadOnly Set to true to only retrieve chats that have unread messages * @param RequestOpts|null $requestOptions * @@ -196,7 +221,7 @@ public function search( int $limit = 50, ?string $query = null, Scope|string $scope = 'titles', - Type|string $type = 'any', + \BeeperDesktop\Chats\ChatSearchParams\Type|string $type = 'any', ?bool $unreadOnly = null, RequestOptions|array|null $requestOptions = null, ): CursorSearch { diff --git a/src/Services/InfoRawService.php b/src/Services/InfoRawService.php index 9ed5030..c5a4228 100644 --- a/src/Services/InfoRawService.php +++ b/src/Services/InfoRawService.php @@ -44,6 +44,7 @@ public function retrieve( path: 'v1/info', options: $requestOptions, convert: InfoGetResponse::class, + security: [], ); } } diff --git a/src/Services/MessagesRawService.php b/src/Services/MessagesRawService.php index 9d379ed..0da852e 100644 --- a/src/Services/MessagesRawService.php +++ b/src/Services/MessagesRawService.php @@ -7,8 +7,8 @@ use BeeperDesktop\Client; use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; -use BeeperDesktop\CursorSortKey; use BeeperDesktop\Message; use BeeperDesktop\Messages\MessageListParams; use BeeperDesktop\Messages\MessageListParams\Direction; @@ -83,7 +83,7 @@ public function update( * }|MessageListParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse> + * @return BaseResponse> * * @throws APIException */ @@ -104,14 +104,14 @@ public function list( query: $parsed, options: $options, convert: Message::class, - page: CursorSortKey::class, + page: CursorNoLimit::class, ); } /** * @api * - * Search messages across chats using Beeper's message index + * Search messages across chats. * * @param array{ * accountIDs?: list, diff --git a/src/Services/MessagesService.php b/src/Services/MessagesService.php index 23d1d14..2045b00 100644 --- a/src/Services/MessagesService.php +++ b/src/Services/MessagesService.php @@ -7,8 +7,8 @@ use BeeperDesktop\Client; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\Core\Util; +use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; -use BeeperDesktop\CursorSortKey; use BeeperDesktop\Message; use BeeperDesktop\Messages\MessageListParams\Direction; use BeeperDesktop\Messages\MessageSearchParams\ChatType; @@ -76,7 +76,7 @@ public function update( * @param Direction|value-of $direction Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided. * @param RequestOpts|null $requestOptions * - * @return CursorSortKey + * @return CursorNoLimit * * @throws APIException */ @@ -85,7 +85,7 @@ public function list( ?string $cursor = null, Direction|string|null $direction = null, RequestOptions|array|null $requestOptions = null, - ): CursorSortKey { + ): CursorNoLimit { $params = Util::removeNulls( ['cursor' => $cursor, 'direction' => $direction] ); @@ -99,7 +99,7 @@ public function list( /** * @api * - * Search messages across chats using Beeper's message index + * Search messages across chats. * * @param list $accountIDs limit search to specific account IDs * @param list $chatIDs limit search to specific chat IDs diff --git a/tests/Services/AssetsTest.php b/tests/Services/AssetsTest.php index 09c9a2e..6aaeb61 100644 --- a/tests/Services/AssetsTest.php +++ b/tests/Services/AssetsTest.php @@ -58,7 +58,7 @@ public function testServe(): void $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertNull($result); + $this->assertIsString($result); } #[Test] @@ -67,7 +67,7 @@ public function testServeWithOptionalParams(): void $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertNull($result); + $this->assertIsString($result); } #[Test] diff --git a/tests/Services/ChatsTest.php b/tests/Services/ChatsTest.php index 5ead909..568e7d6 100644 --- a/tests/Services/ChatsTest.php +++ b/tests/Services/ChatsTest.php @@ -34,7 +34,31 @@ protected function setUp(): void #[Test] public function testCreate(): void { - $result = $this->client->chats->create(); + $result = $this->client->chats->create(accountID: 'accountID'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(ChatNewResponse::class, $result); + } + + #[Test] + public function testCreateWithOptionalParams(): void + { + $result = $this->client->chats->create( + accountID: 'accountID', + allowInvite: true, + messageText: 'messageText', + mode: 'start', + participantIDs: ['string'], + title: 'title', + type: 'single', + user: [ + 'id' => 'id', + 'email' => 'email', + 'fullName' => 'fullName', + 'phoneNumber' => 'phoneNumber', + 'username' => 'username', + ], + ); // @phpstan-ignore-next-line method.alreadyNarrowedType $this->assertInstanceOf(ChatNewResponse::class, $result); diff --git a/tests/Services/MessagesTest.php b/tests/Services/MessagesTest.php index 0d1cab8..f0691c6 100644 --- a/tests/Services/MessagesTest.php +++ b/tests/Services/MessagesTest.php @@ -4,8 +4,8 @@ use BeeperDesktop\Client; use BeeperDesktop\Core\Util; +use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; -use BeeperDesktop\CursorSortKey; use BeeperDesktop\Message; use BeeperDesktop\Messages\MessageSendResponse; use BeeperDesktop\Messages\MessageUpdateResponse; @@ -63,7 +63,7 @@ public function testList(): void $page = $this->client->messages->list('!NCdzlIaMjZUmvmvyHU:beeper.com'); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertInstanceOf(CursorSortKey::class, $page); + $this->assertInstanceOf(CursorNoLimit::class, $page); if ($item = $page->getItems()[0] ?? null) { // @phpstan-ignore-next-line method.alreadyNarrowedType From f271b16d83f129171e6f77aafe06cf6e5b76e6e8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:53:13 +0000 Subject: [PATCH 35/48] Preserve asset serve SDK compatibility --- .stats.yml | 2 +- src/ServiceContracts/AssetsContract.php | 2 +- src/ServiceContracts/AssetsRawContract.php | 2 +- src/Services/AssetsRawService.php | 5 ++--- src/Services/AssetsService.php | 2 +- tests/Services/AssetsTest.php | 4 ++-- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.stats.yml b/.stats.yml index e925f68..1d3cc36 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-611aa7641fbca8cf31d626bf86f9efd3c2b92778e897ebbb25c6ea44185ed1ed.yml -openapi_spec_hash: 4840f003552e8b48eb8e689b59a819ef +openapi_spec_hash: 8dff13848934c5b20f3804236e8286d3 config_hash: 05ebdec072113f63395372504da98192 diff --git a/src/ServiceContracts/AssetsContract.php b/src/ServiceContracts/AssetsContract.php index 029710d..dff92bd 100644 --- a/src/ServiceContracts/AssetsContract.php +++ b/src/ServiceContracts/AssetsContract.php @@ -40,7 +40,7 @@ public function download( public function serve( string $url, RequestOptions|array|null $requestOptions = null - ): string; + ): mixed; /** * @api diff --git a/src/ServiceContracts/AssetsRawContract.php b/src/ServiceContracts/AssetsRawContract.php index b438606..2e7e75d 100644 --- a/src/ServiceContracts/AssetsRawContract.php +++ b/src/ServiceContracts/AssetsRawContract.php @@ -41,7 +41,7 @@ public function download( * @param array|AssetServeParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse + * @return BaseResponse * * @throws APIException */ diff --git a/src/Services/AssetsRawService.php b/src/Services/AssetsRawService.php index 94db5e4..22d415c 100644 --- a/src/Services/AssetsRawService.php +++ b/src/Services/AssetsRawService.php @@ -70,7 +70,7 @@ public function download( * @param array{url: string}|AssetServeParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse + * @return BaseResponse * * @throws APIException */ @@ -88,9 +88,8 @@ public function serve( method: 'get', path: 'v1/assets/serve', query: $parsed, - headers: ['Accept' => 'application/octet-stream'], options: $options, - convert: 'string', + convert: null, ); } diff --git a/src/Services/AssetsService.php b/src/Services/AssetsService.php index 95dfa91..4027449 100644 --- a/src/Services/AssetsService.php +++ b/src/Services/AssetsService.php @@ -69,7 +69,7 @@ public function download( public function serve( string $url, RequestOptions|array|null $requestOptions = null - ): string { + ): mixed { $params = Util::removeNulls(['url' => $url]); // @phpstan-ignore-next-line argument.type diff --git a/tests/Services/AssetsTest.php b/tests/Services/AssetsTest.php index 6aaeb61..09c9a2e 100644 --- a/tests/Services/AssetsTest.php +++ b/tests/Services/AssetsTest.php @@ -58,7 +58,7 @@ public function testServe(): void $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertIsString($result); + $this->assertNull($result); } #[Test] @@ -67,7 +67,7 @@ public function testServeWithOptionalParams(): void $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertIsString($result); + $this->assertNull($result); } #[Test] From bd422f1b90c2cb597b8a56b15c4eb042d0192ced Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 19:54:18 +0000 Subject: [PATCH 36/48] Document asset serve stream response --- .stats.yml | 2 +- src/ServiceContracts/AssetsContract.php | 2 +- src/ServiceContracts/AssetsRawContract.php | 2 +- src/Services/AssetsRawService.php | 5 +++-- src/Services/AssetsService.php | 2 +- tests/Services/AssetsTest.php | 4 ++-- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.stats.yml b/.stats.yml index 1d3cc36..e925f68 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-611aa7641fbca8cf31d626bf86f9efd3c2b92778e897ebbb25c6ea44185ed1ed.yml -openapi_spec_hash: 8dff13848934c5b20f3804236e8286d3 +openapi_spec_hash: 4840f003552e8b48eb8e689b59a819ef config_hash: 05ebdec072113f63395372504da98192 diff --git a/src/ServiceContracts/AssetsContract.php b/src/ServiceContracts/AssetsContract.php index dff92bd..029710d 100644 --- a/src/ServiceContracts/AssetsContract.php +++ b/src/ServiceContracts/AssetsContract.php @@ -40,7 +40,7 @@ public function download( public function serve( string $url, RequestOptions|array|null $requestOptions = null - ): mixed; + ): string; /** * @api diff --git a/src/ServiceContracts/AssetsRawContract.php b/src/ServiceContracts/AssetsRawContract.php index 2e7e75d..b438606 100644 --- a/src/ServiceContracts/AssetsRawContract.php +++ b/src/ServiceContracts/AssetsRawContract.php @@ -41,7 +41,7 @@ public function download( * @param array|AssetServeParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse + * @return BaseResponse * * @throws APIException */ diff --git a/src/Services/AssetsRawService.php b/src/Services/AssetsRawService.php index 22d415c..94db5e4 100644 --- a/src/Services/AssetsRawService.php +++ b/src/Services/AssetsRawService.php @@ -70,7 +70,7 @@ public function download( * @param array{url: string}|AssetServeParams $params * @param RequestOpts|null $requestOptions * - * @return BaseResponse + * @return BaseResponse * * @throws APIException */ @@ -88,8 +88,9 @@ public function serve( method: 'get', path: 'v1/assets/serve', query: $parsed, + headers: ['Accept' => 'application/octet-stream'], options: $options, - convert: null, + convert: 'string', ); } diff --git a/src/Services/AssetsService.php b/src/Services/AssetsService.php index 4027449..95dfa91 100644 --- a/src/Services/AssetsService.php +++ b/src/Services/AssetsService.php @@ -69,7 +69,7 @@ public function download( public function serve( string $url, RequestOptions|array|null $requestOptions = null - ): mixed { + ): string { $params = Util::removeNulls(['url' => $url]); // @phpstan-ignore-next-line argument.type diff --git a/tests/Services/AssetsTest.php b/tests/Services/AssetsTest.php index 09c9a2e..6aaeb61 100644 --- a/tests/Services/AssetsTest.php +++ b/tests/Services/AssetsTest.php @@ -58,7 +58,7 @@ public function testServe(): void $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertNull($result); + $this->assertIsString($result); } #[Test] @@ -67,7 +67,7 @@ public function testServeWithOptionalParams(): void $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType - $this->assertNull($result); + $this->assertIsString($result); } #[Test] From c20da0773b656caba729ada1998a545126d79a2e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 07:52:42 +0000 Subject: [PATCH 37/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index e925f68..a2edbe5 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-611aa7641fbca8cf31d626bf86f9efd3c2b92778e897ebbb25c6ea44185ed1ed.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-fdefa92da44ff91a34438591d022c182a83d9daf9a28b452556e325c6ef7b3f0.yml openapi_spec_hash: 4840f003552e8b48eb8e689b59a819ef config_hash: 05ebdec072113f63395372504da98192 From b202b7a7aaab05d1d4f69b0598f09fac7c9b8f60 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 03:38:34 +0000 Subject: [PATCH 38/48] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index a2edbe5..ec75571 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/beeper-desktop-api-fdefa92da44ff91a34438591d022c182a83d9daf9a28b452556e325c6ef7b3f0.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-356444646dafe352d3ef7c2e01aedf030197a5519b41cf2c3fd8be2571456b43.yml openapi_spec_hash: 4840f003552e8b48eb8e689b59a819ef config_hash: 05ebdec072113f63395372504da98192 From 48ca99875d9640e728922eab3eed6988fcd4ea14 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 4 May 2026 18:06:53 +0000 Subject: [PATCH 39/48] feat(api): api update --- .stats.yml | 8 +- src/Accounts/Account.php | 4 +- src/Accounts/Account/Bridge.php | 14 +- src/Accounts/Account/Bridge/Provider.php | 2 +- src/Chats/ChatCreateParams.php | 145 +++++------------ src/Chats/ChatCreateParams/Mode.php | 15 -- src/Chats/ChatCreateParams/Type.php | 2 +- src/Chats/ChatStartParams.php | 146 ++++++++++++++++++ .../User.php | 4 +- src/Chats/ChatStartResponse.php | 99 ++++++++++++ src/Chats/ChatStartResponse/Status.php | 15 ++ src/ServiceContracts/ChatsContract.php | 39 +++-- src/ServiceContracts/ChatsRawContract.php | 17 ++ src/Services/ChatsRawService.php | 52 +++++-- src/Services/ChatsService.php | 64 +++++--- tests/Services/AssetsTest.php | 9 ++ tests/Services/ChatsTest.php | 58 +++++-- 17 files changed, 501 insertions(+), 192 deletions(-) delete mode 100644 src/Chats/ChatCreateParams/Mode.php create mode 100644 src/Chats/ChatStartParams.php rename src/Chats/{ChatCreateParams => ChatStartParams}/User.php (94%) create mode 100644 src/Chats/ChatStartResponse.php create mode 100644 src/Chats/ChatStartResponse/Status.php diff --git a/.stats.yml b/.stats.yml index ec75571..75ad795 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/beeper-desktop-api-356444646dafe352d3ef7c2e01aedf030197a5519b41cf2c3fd8be2571456b43.yml -openapi_spec_hash: 4840f003552e8b48eb8e689b59a819ef -config_hash: 05ebdec072113f63395372504da98192 +configured_endpoints: 24 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-8b89ffbfeb39b4186328fefd81f7dab1d28c786012201feb8035c7f920c4fbae.yml +openapi_spec_hash: de40e013fcc83fa44d5c51ddecb543c0 +config_hash: 08b781db5f1857ed601d1b2f4b6b45d9 diff --git a/src/Accounts/Account.php b/src/Accounts/Account.php index 8bb48cd..e7979ea 100644 --- a/src/Accounts/Account.php +++ b/src/Accounts/Account.php @@ -36,7 +36,7 @@ final class Account implements BaseModel public string $accountID; /** - * Bridge metadata for the account. Available in Beeper Desktop v4.2.789+. + * Bridge metadata for the account. Available in Beeper Desktop v4.2.799+. */ #[Required] public Bridge $bridge; @@ -109,7 +109,7 @@ public function withAccountID(string $accountID): self } /** - * Bridge metadata for the account. Available in Beeper Desktop v4.2.789+. + * Bridge metadata for the account. Available in Beeper Desktop v4.2.799+. * * @param Bridge|BridgeShape $bridge */ diff --git a/src/Accounts/Account/Bridge.php b/src/Accounts/Account/Bridge.php index 2304404..1283c52 100644 --- a/src/Accounts/Account/Bridge.php +++ b/src/Accounts/Account/Bridge.php @@ -10,7 +10,7 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** - * Bridge metadata for the account. Available in Beeper Desktop v4.2.789+. + * Bridge metadata for the account. Available in Beeper Desktop v4.2.799+. * * @phpstan-type BridgeShape = array{ * id: string, provider: Provider|value-of, type: string @@ -22,13 +22,13 @@ final class Bridge implements BaseModel use SdkModel; /** - * Bridge instance identifier. Available in Beeper Desktop v4.2.789+. + * Bridge instance identifier. Available in Beeper Desktop v4.2.799+. */ #[Required] public string $id; /** - * Bridge provider for the account. Available in Beeper Desktop v4.2.789+. + * Bridge provider for the account. Available in Beeper Desktop v4.2.799+. * * @var value-of $provider */ @@ -36,7 +36,7 @@ final class Bridge implements BaseModel public string $provider; /** - * Bridge type. Available in Beeper Desktop v4.2.789+. + * Bridge type. Available in Beeper Desktop v4.2.799+. */ #[Required] public string $type; @@ -82,7 +82,7 @@ public static function with( } /** - * Bridge instance identifier. Available in Beeper Desktop v4.2.789+. + * Bridge instance identifier. Available in Beeper Desktop v4.2.799+. */ public function withID(string $id): self { @@ -93,7 +93,7 @@ public function withID(string $id): self } /** - * Bridge provider for the account. Available in Beeper Desktop v4.2.789+. + * Bridge provider for the account. Available in Beeper Desktop v4.2.799+. * * @param Provider|value-of $provider */ @@ -106,7 +106,7 @@ public function withProvider(Provider|string $provider): self } /** - * Bridge type. Available in Beeper Desktop v4.2.789+. + * Bridge type. Available in Beeper Desktop v4.2.799+. */ public function withType(string $type): self { diff --git a/src/Accounts/Account/Bridge/Provider.php b/src/Accounts/Account/Bridge/Provider.php index fcf152d..9a0fa83 100644 --- a/src/Accounts/Account/Bridge/Provider.php +++ b/src/Accounts/Account/Bridge/Provider.php @@ -5,7 +5,7 @@ namespace BeeperDesktop\Accounts\Account\Bridge; /** - * Bridge provider for the account. Available in Beeper Desktop v4.2.789+. + * Bridge provider for the account. Available in Beeper Desktop v4.2.799+. */ enum Provider: string { diff --git a/src/Chats/ChatCreateParams.php b/src/Chats/ChatCreateParams.php index c3ae9eb..b2088bf 100644 --- a/src/Chats/ChatCreateParams.php +++ b/src/Chats/ChatCreateParams.php @@ -4,9 +4,7 @@ namespace BeeperDesktop\Chats; -use BeeperDesktop\Chats\ChatCreateParams\Mode; use BeeperDesktop\Chats\ChatCreateParams\Type; -use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Attributes\Required; use BeeperDesktop\Core\Concerns\SdkModel; @@ -14,21 +12,16 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** - * Create a direct or group chat with mode="create", or use mode="start" to resolve a contact and open a direct chat. + * Create a direct or group chat from participant IDs. * * @see BeeperDesktop\Services\ChatsService::create() * - * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User - * * @phpstan-type ChatCreateParamsShape = array{ * accountID: string, - * allowInvite?: bool|null, + * participantIDs: list, + * type: Type|value-of, * messageText?: string|null, - * mode?: null|Mode|value-of, - * participantIDs?: list|null, * title?: string|null, - * type?: null|Type|value-of, - * user?: null|User|UserShape, * } */ final class ChatCreateParams implements BaseModel @@ -44,65 +37,48 @@ final class ChatCreateParams implements BaseModel public string $accountID; /** - * Only used for mode='start'. Whether invite-based DM creation is allowed when required by the platform. - */ - #[Optional] - public ?bool $allowInvite; - - /** - * Optional first message content if the platform requires it to create the chat. - */ - #[Optional] - public ?string $messageText; - - /** - * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. Omit or set 'create' to create a chat directly. + * User IDs to include in the new chat. * - * @var value-of|null $mode + * @var list $participantIDs */ - #[Optional(enum: Mode::class)] - public ?string $mode; + #[Required(list: 'string')] + public array $participantIDs; /** - * Required for create mode. Provide exactly one user ID for 'single' chats and one or more for 'group' chats. + * 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. * - * @var list|null $participantIDs + * @var value-of $type */ - #[Optional(list: 'string')] - public ?array $participantIDs; + #[Required(enum: Type::class)] + public string $type; /** - * Optional title for group chats; ignored for single chats on most networks. + * Optional first message content if the platform requires it to create the chat. */ #[Optional] - public ?string $title; - - /** - * Required for create mode. 'single' creates a direct message chat; 'group' creates a group chat. - * - * @var value-of|null $type - */ - #[Optional(enum: Type::class)] - public ?string $type; + public ?string $messageText; /** - * Required for mode='start'. Merged user-like contact payload used to resolve the best identifier. + * Optional title for group chats; ignored for single chats on most networks. */ #[Optional] - public ?User $user; + public ?string $title; /** * `new ChatCreateParams()` is missing required properties by the API. * * To enforce required parameters use * ``` - * ChatCreateParams::with(accountID: ...) + * ChatCreateParams::with(accountID: ..., participantIDs: ..., type: ...) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new ChatCreateParams)->withAccountID(...) + * (new ChatCreateParams) + * ->withAccountID(...) + * ->withParticipantIDs(...) + * ->withType(...) * ``` */ public function __construct() @@ -115,32 +91,24 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param Mode|value-of|null $mode - * @param list|null $participantIDs - * @param Type|value-of|null $type - * @param User|UserShape|null $user + * @param list $participantIDs + * @param Type|value-of $type */ public static function with( string $accountID, - ?bool $allowInvite = null, + array $participantIDs, + Type|string $type, ?string $messageText = null, - Mode|string|null $mode = null, - ?array $participantIDs = null, ?string $title = null, - Type|string|null $type = null, - User|array|null $user = null, ): self { $self = new self; $self['accountID'] = $accountID; + $self['participantIDs'] = $participantIDs; + $self['type'] = $type; - null !== $allowInvite && $self['allowInvite'] = $allowInvite; null !== $messageText && $self['messageText'] = $messageText; - null !== $mode && $self['mode'] = $mode; - null !== $participantIDs && $self['participantIDs'] = $participantIDs; null !== $title && $self['title'] = $title; - null !== $type && $self['type'] = $type; - null !== $user && $self['user'] = $user; return $self; } @@ -157,42 +125,7 @@ public function withAccountID(string $accountID): self } /** - * Only used for mode='start'. Whether invite-based DM creation is allowed when required by the platform. - */ - public function withAllowInvite(bool $allowInvite): self - { - $self = clone $this; - $self['allowInvite'] = $allowInvite; - - return $self; - } - - /** - * Optional first message content if the platform requires it to create the chat. - */ - public function withMessageText(string $messageText): self - { - $self = clone $this; - $self['messageText'] = $messageText; - - return $self; - } - - /** - * Operation mode. Use 'start' to resolve a user/contact and start a direct chat. Omit or set 'create' to create a chat directly. - * - * @param Mode|value-of $mode - */ - public function withMode(Mode|string $mode): self - { - $self = clone $this; - $self['mode'] = $mode; - - return $self; - } - - /** - * Required for create mode. Provide exactly one user ID for 'single' chats and one or more for 'group' chats. + * User IDs to include in the new chat. * * @param list $participantIDs */ @@ -205,38 +138,36 @@ public function withParticipantIDs(array $participantIDs): self } /** - * Optional title for group chats; ignored for single chats on most networks. + * 'single' requires exactly one participantID; 'group' supports multiple participants and optional title. + * + * @param Type|value-of $type */ - public function withTitle(string $title): self + public function withType(Type|string $type): self { $self = clone $this; - $self['title'] = $title; + $self['type'] = $type; return $self; } /** - * Required for create mode. 'single' creates a direct message chat; 'group' creates a group chat. - * - * @param Type|value-of $type + * Optional first message content if the platform requires it to create the chat. */ - public function withType(Type|string $type): self + public function withMessageText(string $messageText): self { $self = clone $this; - $self['type'] = $type; + $self['messageText'] = $messageText; return $self; } /** - * Required for mode='start'. Merged user-like contact payload used to resolve the best identifier. - * - * @param User|UserShape $user + * Optional title for group chats; ignored for single chats on most networks. */ - public function withUser(User|array $user): self + public function withTitle(string $title): self { $self = clone $this; - $self['user'] = $user; + $self['title'] = $title; return $self; } diff --git a/src/Chats/ChatCreateParams/Mode.php b/src/Chats/ChatCreateParams/Mode.php deleted file mode 100644 index 04f50d3..0000000 --- a/src/Chats/ChatCreateParams/Mode.php +++ /dev/null @@ -1,15 +0,0 @@ - */ + use SdkModel; + use SdkParams; + + /** + * Account to create or start the chat on. + */ + #[Required] + public string $accountID; + + /** + * Merged user-like contact payload used to resolve the best identifier. + */ + #[Required] + public User $user; + + /** + * Whether invite-based DM creation is allowed when required by the platform. + */ + #[Optional] + public ?bool $allowInvite; + + /** + * Optional first message content if the platform requires it to create the chat. + */ + #[Optional] + public ?string $messageText; + + /** + * `new ChatStartParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * ChatStartParams::with(accountID: ..., user: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new ChatStartParams)->withAccountID(...)->withUser(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param User|UserShape $user + */ + public static function with( + string $accountID, + User|array $user, + ?bool $allowInvite = null, + ?string $messageText = null, + ): self { + $self = new self; + + $self['accountID'] = $accountID; + $self['user'] = $user; + + null !== $allowInvite && $self['allowInvite'] = $allowInvite; + null !== $messageText && $self['messageText'] = $messageText; + + return $self; + } + + /** + * Account to create or start the chat on. + */ + public function withAccountID(string $accountID): self + { + $self = clone $this; + $self['accountID'] = $accountID; + + return $self; + } + + /** + * Merged user-like contact payload used to resolve the best identifier. + * + * @param User|UserShape $user + */ + public function withUser(User|array $user): self + { + $self = clone $this; + $self['user'] = $user; + + return $self; + } + + /** + * Whether invite-based DM creation is allowed when required by the platform. + */ + public function withAllowInvite(bool $allowInvite): self + { + $self = clone $this; + $self['allowInvite'] = $allowInvite; + + return $self; + } + + /** + * Optional first message content if the platform requires it to create the chat. + */ + public function withMessageText(string $messageText): self + { + $self = clone $this; + $self['messageText'] = $messageText; + + return $self; + } +} diff --git a/src/Chats/ChatCreateParams/User.php b/src/Chats/ChatStartParams/User.php similarity index 94% rename from src/Chats/ChatCreateParams/User.php rename to src/Chats/ChatStartParams/User.php index f39d8ca..fdd9f55 100644 --- a/src/Chats/ChatCreateParams/User.php +++ b/src/Chats/ChatStartParams/User.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace BeeperDesktop\Chats\ChatCreateParams; +namespace BeeperDesktop\Chats\ChatStartParams; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Contracts\BaseModel; /** - * Required for mode='start'. Merged user-like contact payload used to resolve the best identifier. + * Merged user-like contact payload used to resolve the best identifier. * * @phpstan-type UserShape = array{ * id?: string|null, diff --git a/src/Chats/ChatStartResponse.php b/src/Chats/ChatStartResponse.php new file mode 100644 index 0000000..0d3f44e --- /dev/null +++ b/src/Chats/ChatStartResponse.php @@ -0,0 +1,99 @@ + + * } + */ +final class ChatStartResponse implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Newly created chat ID. + */ + #[Required] + public string $chatID; + + /** + * Only returned in start mode. 'existing' means an existing chat was reused; 'created' means a new chat was created. + * + * @var value-of|null $status + */ + #[Optional(enum: Status::class)] + public ?string $status; + + /** + * `new ChatStartResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * ChatStartResponse::with(chatID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new ChatStartResponse)->withChatID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Status|value-of|null $status + */ + public static function with( + string $chatID, + Status|string|null $status = null + ): self { + $self = new self; + + $self['chatID'] = $chatID; + + null !== $status && $self['status'] = $status; + + return $self; + } + + /** + * Newly created chat ID. + */ + public function withChatID(string $chatID): self + { + $self = clone $this; + $self['chatID'] = $chatID; + + return $self; + } + + /** + * Only returned in start mode. 'existing' means an existing chat was reused; 'created' means a new chat was created. + * + * @param Status|value-of $status + */ + public function withStatus(Status|string $status): self + { + $self = clone $this; + $self['status'] = $status; + + return $self; + } +} diff --git a/src/Chats/ChatStartResponse/Status.php b/src/Chats/ChatStartResponse/Status.php new file mode 100644 index 0000000..88baf8e --- /dev/null +++ b/src/Chats/ChatStartResponse/Status.php @@ -0,0 +1,15 @@ + $participantIDs user IDs to include in the new chat + * @param Type|value-of $type 'single' requires exactly one participantID; 'group' supports multiple participants and optional title * @param string $messageText optional first message content if the platform requires it to create the chat - * @param Mode|value-of $mode Operation mode. Use 'start' to resolve a user/contact and start a direct chat. Omit or set 'create' to create a chat directly. - * @param list $participantIDs Required for create mode. Provide exactly one user ID for 'single' chats and one or more for 'group' chats. * @param string $title optional title for group chats; ignored for single chats on most networks - * @param Type|value-of $type Required for create mode. 'single' creates a direct message chat; 'group' creates a group chat. - * @param User|UserShape $user Required for mode='start'. Merged user-like contact payload used to resolve the best identifier. * @param RequestOpts|null $requestOptions * * @throws APIException */ public function create( string $accountID, - bool $allowInvite = true, + array $participantIDs, + Type|string $type, ?string $messageText = null, - Mode|string|null $mode = null, - ?array $participantIDs = null, ?string $title = null, - Type|string|null $type = null, - User|array|null $user = null, RequestOptions|array|null $requestOptions = null, ): ChatNewResponse; @@ -136,4 +130,23 @@ public function search( ?bool $unreadOnly = null, RequestOptions|array|null $requestOptions = null, ): CursorSearch; + + /** + * @api + * + * @param string $accountID account to create or start the chat on + * @param User|UserShape $user merged user-like contact payload used to resolve the best identifier + * @param bool $allowInvite whether invite-based DM creation is allowed when required by the platform + * @param string $messageText optional first message content if the platform requires it to create the chat + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function start( + string $accountID, + User|array $user, + bool $allowInvite = true, + ?string $messageText = null, + RequestOptions|array|null $requestOptions = null, + ): ChatStartResponse; } diff --git a/src/ServiceContracts/ChatsRawContract.php b/src/ServiceContracts/ChatsRawContract.php index 70e29b1..5c11e05 100644 --- a/src/ServiceContracts/ChatsRawContract.php +++ b/src/ServiceContracts/ChatsRawContract.php @@ -12,6 +12,8 @@ use BeeperDesktop\Chats\ChatNewResponse; use BeeperDesktop\Chats\ChatRetrieveParams; use BeeperDesktop\Chats\ChatSearchParams; +use BeeperDesktop\Chats\ChatStartParams; +use BeeperDesktop\Chats\ChatStartResponse; use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\CursorNoLimit; @@ -101,4 +103,19 @@ public function search( array|ChatSearchParams $params, RequestOptions|array|null $requestOptions = null, ): BaseResponse; + + /** + * @api + * + * @param array|ChatStartParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function start( + array|ChatStartParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; } diff --git a/src/Services/ChatsRawService.php b/src/Services/ChatsRawService.php index 3140e67..c06ceee 100644 --- a/src/Services/ChatsRawService.php +++ b/src/Services/ChatsRawService.php @@ -7,9 +7,7 @@ use BeeperDesktop\Chats\Chat; use BeeperDesktop\Chats\ChatArchiveParams; use BeeperDesktop\Chats\ChatCreateParams; -use BeeperDesktop\Chats\ChatCreateParams\Mode; use BeeperDesktop\Chats\ChatCreateParams\Type; -use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Chats\ChatListParams; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; @@ -18,6 +16,9 @@ use BeeperDesktop\Chats\ChatSearchParams; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; +use BeeperDesktop\Chats\ChatStartParams; +use BeeperDesktop\Chats\ChatStartParams\User; +use BeeperDesktop\Chats\ChatStartResponse; use BeeperDesktop\Client; use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; @@ -29,7 +30,7 @@ /** * Manage chats. * - * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatStartParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class ChatsRawService implements ChatsRawContract @@ -43,17 +44,14 @@ public function __construct(private Client $client) {} /** * @api * - * Create a direct or group chat with mode="create", or use mode="start" to resolve a contact and open a direct chat. + * Create a direct or group chat from participant IDs. * * @param array{ * accountID: string, - * allowInvite?: bool, + * participantIDs: list, + * type: Type|value-of, * messageText?: string, - * mode?: Mode|value-of, - * participantIDs?: list, * title?: string, - * type?: Type|value-of, - * user?: User|UserShape, * }|ChatCreateParams $params * @param RequestOpts|null $requestOptions * @@ -226,4 +224,40 @@ public function search( page: CursorSearch::class, ); } + + /** + * @api + * + * Resolve a user/contact and open a direct chat. Reuses an existing direct chat when one is found. Available in Beeper Desktop v4.2.799+. + * + * @param array{ + * accountID: string, + * user: User|UserShape, + * allowInvite?: bool, + * messageText?: string, + * }|ChatStartParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function start( + array|ChatStartParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = ChatStartParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/chats.start', + body: (object) $parsed, + options: $options, + convert: ChatStartResponse::class, + ); + } } diff --git a/src/Services/ChatsService.php b/src/Services/ChatsService.php index 9f7169e..51fdd92 100644 --- a/src/Services/ChatsService.php +++ b/src/Services/ChatsService.php @@ -5,14 +5,14 @@ namespace BeeperDesktop\Services; use BeeperDesktop\Chats\Chat; -use BeeperDesktop\Chats\ChatCreateParams\Mode; use BeeperDesktop\Chats\ChatCreateParams\Type; -use BeeperDesktop\Chats\ChatCreateParams\User; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; use BeeperDesktop\Chats\ChatNewResponse; use BeeperDesktop\Chats\ChatSearchParams\Inbox; use BeeperDesktop\Chats\ChatSearchParams\Scope; +use BeeperDesktop\Chats\ChatStartParams\User; +use BeeperDesktop\Chats\ChatStartResponse; use BeeperDesktop\Client; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\Core\Util; @@ -26,7 +26,7 @@ /** * Manage chats. * - * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatCreateParams\User + * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatStartParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ final class ChatsService implements ChatsContract @@ -59,41 +59,32 @@ public function __construct(private Client $client) /** * @api * - * Create a direct or group chat with mode="create", or use mode="start" to resolve a contact and open a direct chat. + * Create a direct or group chat from participant IDs. * * @param string $accountID account to create or start the chat on - * @param bool $allowInvite Only used for mode='start'. Whether invite-based DM creation is allowed when required by the platform. + * @param list $participantIDs user IDs to include in the new chat + * @param Type|value-of $type 'single' requires exactly one participantID; 'group' supports multiple participants and optional title * @param string $messageText optional first message content if the platform requires it to create the chat - * @param Mode|value-of $mode Operation mode. Use 'start' to resolve a user/contact and start a direct chat. Omit or set 'create' to create a chat directly. - * @param list $participantIDs Required for create mode. Provide exactly one user ID for 'single' chats and one or more for 'group' chats. * @param string $title optional title for group chats; ignored for single chats on most networks - * @param Type|value-of $type Required for create mode. 'single' creates a direct message chat; 'group' creates a group chat. - * @param User|UserShape $user Required for mode='start'. Merged user-like contact payload used to resolve the best identifier. * @param RequestOpts|null $requestOptions * * @throws APIException */ public function create( string $accountID, - bool $allowInvite = true, + array $participantIDs, + Type|string $type, ?string $messageText = null, - Mode|string|null $mode = null, - ?array $participantIDs = null, ?string $title = null, - Type|string|null $type = null, - User|array|null $user = null, RequestOptions|array|null $requestOptions = null, ): ChatNewResponse { $params = Util::removeNulls( [ 'accountID' => $accountID, - 'allowInvite' => $allowInvite, - 'messageText' => $messageText, - 'mode' => $mode, 'participantIDs' => $participantIDs, - 'title' => $title, 'type' => $type, - 'user' => $user, + 'messageText' => $messageText, + 'title' => $title, ], ); @@ -247,4 +238,39 @@ public function search( return $response->parse(); } + + /** + * @api + * + * Resolve a user/contact and open a direct chat. Reuses an existing direct chat when one is found. Available in Beeper Desktop v4.2.799+. + * + * @param string $accountID account to create or start the chat on + * @param User|UserShape $user merged user-like contact payload used to resolve the best identifier + * @param bool $allowInvite whether invite-based DM creation is allowed when required by the platform + * @param string $messageText optional first message content if the platform requires it to create the chat + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function start( + string $accountID, + User|array $user, + bool $allowInvite = true, + ?string $messageText = null, + RequestOptions|array|null $requestOptions = null, + ): ChatStartResponse { + $params = Util::removeNulls( + [ + 'accountID' => $accountID, + 'user' => $user, + 'allowInvite' => $allowInvite, + 'messageText' => $messageText, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->start(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } } diff --git a/tests/Services/AssetsTest.php b/tests/Services/AssetsTest.php index 6aaeb61..66e0c1f 100644 --- a/tests/Services/AssetsTest.php +++ b/tests/Services/AssetsTest.php @@ -11,6 +11,7 @@ use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use Tests\UnsupportedMockTests; /** * @internal @@ -55,6 +56,10 @@ public function testDownloadWithOptionalParams(): void #[Test] public function testServe(): void { + if (UnsupportedMockTests::$skip) { + $this->markTestSkipped('Generated PHP mock test parses the binary stream response as null despite the OpenAPI response being application/octet-stream format=binary.'); + } + $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType @@ -64,6 +69,10 @@ public function testServe(): void #[Test] public function testServeWithOptionalParams(): void { + if (UnsupportedMockTests::$skip) { + $this->markTestSkipped('Generated PHP mock test parses the binary stream response as null despite the OpenAPI response being application/octet-stream format=binary.'); + } + $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType diff --git a/tests/Services/ChatsTest.php b/tests/Services/ChatsTest.php index 568e7d6..3b7fbfa 100644 --- a/tests/Services/ChatsTest.php +++ b/tests/Services/ChatsTest.php @@ -5,6 +5,7 @@ use BeeperDesktop\Chats\Chat; use BeeperDesktop\Chats\ChatListResponse; use BeeperDesktop\Chats\ChatNewResponse; +use BeeperDesktop\Chats\ChatStartResponse; use BeeperDesktop\Client; use BeeperDesktop\Core\Util; use BeeperDesktop\CursorNoLimit; @@ -12,6 +13,7 @@ use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use Tests\UnsupportedMockTests; /** * @internal @@ -34,7 +36,11 @@ protected function setUp(): void #[Test] public function testCreate(): void { - $result = $this->client->chats->create(accountID: 'accountID'); + $result = $this->client->chats->create( + accountID: 'accountID', + participantIDs: ['string'], + type: 'single' + ); // @phpstan-ignore-next-line method.alreadyNarrowedType $this->assertInstanceOf(ChatNewResponse::class, $result); @@ -45,19 +51,10 @@ public function testCreateWithOptionalParams(): void { $result = $this->client->chats->create( accountID: 'accountID', - allowInvite: true, - messageText: 'messageText', - mode: 'start', participantIDs: ['string'], - title: 'title', type: 'single', - user: [ - 'id' => 'id', - 'email' => 'email', - 'fullName' => 'fullName', - 'phoneNumber' => 'phoneNumber', - 'username' => 'username', - ], + messageText: 'messageText', + title: 'title', ); // @phpstan-ignore-next-line method.alreadyNarrowedType @@ -109,4 +106,41 @@ public function testSearch(): void $this->assertInstanceOf(Chat::class, $item); } } + + #[Test] + public function testStart(): void + { + if (UnsupportedMockTests::$skip) { + $this->markTestSkipped('Stainless mock tests currently load the project-published OpenAPI spec URL, which may not include newly-added local-only endpoints during build checks.'); + } + + $result = $this->client->chats->start(accountID: 'accountID', user: []); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(ChatStartResponse::class, $result); + } + + #[Test] + public function testStartWithOptionalParams(): void + { + if (UnsupportedMockTests::$skip) { + $this->markTestSkipped('Stainless mock tests currently load the project-published OpenAPI spec URL, which may not include newly-added local-only endpoints during build checks.'); + } + + $result = $this->client->chats->start( + accountID: 'accountID', + user: [ + 'id' => 'id', + 'email' => 'email', + 'fullName' => 'fullName', + 'phoneNumber' => 'phoneNumber', + 'username' => 'username', + ], + allowInvite: true, + messageText: 'messageText', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(ChatStartResponse::class, $result); + } } From d5d89549d1dcdb03ebd079062c25917f76de162e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 21:17:35 +0000 Subject: [PATCH 40/48] feat(api): api update --- .stats.yml | 8 +- README.md | 13 +- src/Accounts/Account.php | 8 +- src/Accounts/Account/Bridge.php | 14 +- src/Accounts/Account/Bridge/Provider.php | 2 +- src/Assets/AssetDownloadParams.php | 6 +- src/Assets/AssetDownloadResponse.php | 4 +- src/Assets/AssetServeParams.php | 4 +- src/Assets/AssetUploadBase64Params.php | 2 +- src/Assets/AssetUploadBase64Response.php | 8 +- src/Assets/AssetUploadParams.php | 2 +- src/Assets/AssetUploadResponse.php | 8 +- src/Attachment.php | 33 +- src/Attachment/Transcription.php | 113 +++ src/BeeperDesktopFocusParams.php | 10 +- src/Chats/Chat.php | 262 +++++++ src/Chats/Chat/Capabilities.php | 665 ++++++++++++++++++ src/Chats/Chat/Capabilities/Attachment.php | 228 ++++++ .../Chat/Capabilities/Attachment/Caption.php | 21 + .../Chat/Capabilities/Attachment/MimeType.php | 21 + src/Chats/Chat/Capabilities/Delete.php | 21 + .../Chat/Capabilities/DisappearingTimer.php | 111 +++ .../Capabilities/DisappearingTimer/Type.php | 12 + src/Chats/Chat/Capabilities/Edit.php | 21 + src/Chats/Chat/Capabilities/Formatting.php | 21 + .../Chat/Capabilities/LocationMessage.php | 21 + .../Chat/Capabilities/MessageRequest.php | 94 +++ .../MessageRequest/AcceptWithButton.php | 21 + .../MessageRequest/AcceptWithMessage.php | 21 + .../Chat/Capabilities/ParticipantActions.php | 170 +++++ .../Capabilities/ParticipantActions/Ban.php | 21 + .../ParticipantActions/Invite.php | 21 + .../Capabilities/ParticipantActions/Kick.php | 21 + .../Capabilities/ParticipantActions/Leave.php | 21 + .../ParticipantActions/RevokeInvite.php | 21 + src/Chats/Chat/Capabilities/Poll.php | 21 + src/Chats/Chat/Capabilities/Reaction.php | 21 + src/Chats/Chat/Capabilities/Reply.php | 21 + src/Chats/Chat/Capabilities/State.php | 142 ++++ src/Chats/Chat/Capabilities/State/Avatar.php | 77 ++ .../Chat/Capabilities/State/Avatar/Level.php | 21 + .../Chat/Capabilities/State/Description.php | 77 ++ .../Capabilities/State/Description/Level.php | 21 + .../Capabilities/State/DisappearingTimer.php | 77 ++ .../State/DisappearingTimer/Level.php | 21 + src/Chats/Chat/Capabilities/State/Title.php | 77 ++ .../Chat/Capabilities/State/Title/Level.php | 21 + src/Chats/Chat/Capabilities/Thread.php | 21 + src/Chats/Chat/Draft.php | 101 +++ src/Chats/Chat/Draft/Attachment.php | 246 +++++++ src/Chats/Chat/Draft/Attachment/Size.php | 62 ++ src/Chats/Chat/Draft/Attachment/Type.php | 17 + src/Chats/Chat/Participants.php | 14 +- src/Chats/Chat/Participants/Item.php | 275 ++++++++ src/Chats/Chat/Reminder.php | 79 +++ src/Chats/Chat/Snooze.php | 78 ++ src/Chats/ChatCreateParams.php | 2 +- src/Chats/ChatListResponse.php | 264 +++++++ src/Chats/ChatMarkReadParams.php | 60 ++ src/Chats/ChatMarkUnreadParams.php | 60 ++ src/Chats/ChatNewResponse.php | 551 ++++++++++++++- src/Chats/ChatNewResponse/Status.php | 4 +- src/Chats/ChatRetrieveParams.php | 4 +- src/Chats/ChatStartParams.php | 2 +- src/Chats/ChatStartResponse.php | 551 ++++++++++++++- src/Chats/ChatStartResponse/Status.php | 4 +- src/Chats/ChatUpdateParams.php | 230 ++++++ src/Chats/ChatUpdateParams/Draft.php | 101 +++ .../ChatUpdateParams/Draft/Attachment.php | 206 ++++++ .../Draft/Attachment/Size.php | 76 ++ .../Draft/Attachment/Type.php | 25 + .../Messages/Reactions/ReactionAddParams.php | 8 +- .../Reactions/ReactionAddResponse.php | 12 +- .../Reactions/ReactionDeleteParams.php | 24 +- .../Reactions/ReactionDeleteResponse.php | 8 +- .../ReminderCreateParams/Reminder.php | 20 +- src/Client.php | 6 +- src/Info/InfoGetResponse/Server.php | 4 +- src/Message.php | 178 ++++- src/Message/Link.php | 202 ++++++ src/Message/Link/ImgSize.php | 62 ++ src/Message/Seen.php | 34 + src/Message/Seen/MessageSeenByParticipant.php | 28 + src/Message/SendStatus.php | 187 +++++ src/Message/SendStatus/Status.php | 19 + src/Messages/MessageDeleteParams.php | 96 +++ src/Messages/MessageRetrieveParams.php | 74 ++ src/Messages/MessageSendParams.php | 4 +- src/Messages/MessageSendParams/Attachment.php | 4 +- .../MessageSendParams/Attachment/Type.php | 12 +- src/Messages/MessageSendResponse.php | 8 +- src/Messages/MessageUpdateParams.php | 4 +- src/Messages/MessageUpdateResponse.php | 488 ++++++++++++- src/Reaction.php | 4 +- src/ServiceContracts/AssetsContract.php | 4 +- .../BeeperDesktopClientContract.php | 4 +- .../Chats/Messages/ReactionsContract.php | 16 +- .../Chats/Messages/ReactionsRawContract.php | 6 +- .../Chats/RemindersContract.php | 4 +- .../Chats/RemindersRawContract.php | 4 +- src/ServiceContracts/ChatsContract.php | 84 ++- src/ServiceContracts/ChatsRawContract.php | 73 +- src/ServiceContracts/MessagesContract.php | 42 +- src/ServiceContracts/MessagesRawContract.php | 42 +- src/Services/AccountsRawService.php | 2 +- src/Services/AccountsService.php | 2 +- src/Services/AssetsRawService.php | 6 +- src/Services/AssetsService.php | 10 +- .../BeeperDesktopClientRawService.php | 4 +- src/Services/BeeperDesktopClientService.php | 8 +- .../Chats/Messages/ReactionsRawService.php | 18 +- .../Chats/Messages/ReactionsService.php | 20 +- src/Services/Chats/RemindersRawService.php | 4 +- src/Services/Chats/RemindersService.php | 4 +- src/Services/ChatsRawService.php | 149 +++- src/Services/ChatsService.php | 134 +++- src/Services/InfoRawService.php | 4 +- src/Services/InfoService.php | 4 +- src/Services/MessagesRawService.php | 79 ++- src/Services/MessagesService.php | 62 +- src/User.php | 4 +- tests/Services/AssetsTest.php | 9 - .../Services/Chats/Messages/ReactionsTest.php | 12 +- tests/Services/Chats/RemindersTest.php | 9 +- tests/Services/ChatsTest.php | 49 +- tests/Services/MessagesTest.php | 53 +- 126 files changed, 7825 insertions(+), 266 deletions(-) create mode 100644 src/Attachment/Transcription.php create mode 100644 src/Chats/Chat/Capabilities.php create mode 100644 src/Chats/Chat/Capabilities/Attachment.php create mode 100644 src/Chats/Chat/Capabilities/Attachment/Caption.php create mode 100644 src/Chats/Chat/Capabilities/Attachment/MimeType.php create mode 100644 src/Chats/Chat/Capabilities/Delete.php create mode 100644 src/Chats/Chat/Capabilities/DisappearingTimer.php create mode 100644 src/Chats/Chat/Capabilities/DisappearingTimer/Type.php create mode 100644 src/Chats/Chat/Capabilities/Edit.php create mode 100644 src/Chats/Chat/Capabilities/Formatting.php create mode 100644 src/Chats/Chat/Capabilities/LocationMessage.php create mode 100644 src/Chats/Chat/Capabilities/MessageRequest.php create mode 100644 src/Chats/Chat/Capabilities/MessageRequest/AcceptWithButton.php create mode 100644 src/Chats/Chat/Capabilities/MessageRequest/AcceptWithMessage.php create mode 100644 src/Chats/Chat/Capabilities/ParticipantActions.php create mode 100644 src/Chats/Chat/Capabilities/ParticipantActions/Ban.php create mode 100644 src/Chats/Chat/Capabilities/ParticipantActions/Invite.php create mode 100644 src/Chats/Chat/Capabilities/ParticipantActions/Kick.php create mode 100644 src/Chats/Chat/Capabilities/ParticipantActions/Leave.php create mode 100644 src/Chats/Chat/Capabilities/ParticipantActions/RevokeInvite.php create mode 100644 src/Chats/Chat/Capabilities/Poll.php create mode 100644 src/Chats/Chat/Capabilities/Reaction.php create mode 100644 src/Chats/Chat/Capabilities/Reply.php create mode 100644 src/Chats/Chat/Capabilities/State.php create mode 100644 src/Chats/Chat/Capabilities/State/Avatar.php create mode 100644 src/Chats/Chat/Capabilities/State/Avatar/Level.php create mode 100644 src/Chats/Chat/Capabilities/State/Description.php create mode 100644 src/Chats/Chat/Capabilities/State/Description/Level.php create mode 100644 src/Chats/Chat/Capabilities/State/DisappearingTimer.php create mode 100644 src/Chats/Chat/Capabilities/State/DisappearingTimer/Level.php create mode 100644 src/Chats/Chat/Capabilities/State/Title.php create mode 100644 src/Chats/Chat/Capabilities/State/Title/Level.php create mode 100644 src/Chats/Chat/Capabilities/Thread.php create mode 100644 src/Chats/Chat/Draft.php create mode 100644 src/Chats/Chat/Draft/Attachment.php create mode 100644 src/Chats/Chat/Draft/Attachment/Size.php create mode 100644 src/Chats/Chat/Draft/Attachment/Type.php create mode 100644 src/Chats/Chat/Participants/Item.php create mode 100644 src/Chats/Chat/Reminder.php create mode 100644 src/Chats/Chat/Snooze.php create mode 100644 src/Chats/ChatMarkReadParams.php create mode 100644 src/Chats/ChatMarkUnreadParams.php create mode 100644 src/Chats/ChatUpdateParams.php create mode 100644 src/Chats/ChatUpdateParams/Draft.php create mode 100644 src/Chats/ChatUpdateParams/Draft/Attachment.php create mode 100644 src/Chats/ChatUpdateParams/Draft/Attachment/Size.php create mode 100644 src/Chats/ChatUpdateParams/Draft/Attachment/Type.php create mode 100644 src/Message/Link.php create mode 100644 src/Message/Link/ImgSize.php create mode 100644 src/Message/Seen.php create mode 100644 src/Message/Seen/MessageSeenByParticipant.php create mode 100644 src/Message/SendStatus.php create mode 100644 src/Message/SendStatus/Status.php create mode 100644 src/Messages/MessageDeleteParams.php create mode 100644 src/Messages/MessageRetrieveParams.php diff --git a/.stats.yml b/.stats.yml index 75ad795..2dd3fee 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 24 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-8b89ffbfeb39b4186328fefd81f7dab1d28c786012201feb8035c7f920c4fbae.yml -openapi_spec_hash: de40e013fcc83fa44d5c51ddecb543c0 -config_hash: 08b781db5f1857ed601d1b2f4b6b45d9 +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 diff --git a/README.md b/README.md index e90f056..7ae7d70 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,14 @@ $client = new Client( accessToken: getenv('BEEPER_ACCESS_TOKEN') ?: 'My Access Token' ); -$page = $client->chats->search(includeMuted: true, limit: 3, type: 'single'); +$page = $client->chats->search( + accountIDs: [ + 'matrix', 'discordgo', 'local-whatsapp_ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc' + ], + includeMuted: true, + limit: 3, + type: 'single', +); var_dump($page->id); ``` @@ -70,9 +77,9 @@ $client = new Client( ); $page = $client->messages->search( - accountIDs: ['local-telegram_ba_QFrb5lrLPhO3OT5MFBeTWv0x4BI'], + accountIDs: ['discordgo', 'local-whatsapp_ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc'], limit: 10, - query: 'deployment', + query: 'oauth', ); var_dump($page); diff --git a/src/Accounts/Account.php b/src/Accounts/Account.php index e7979ea..6d4c449 100644 --- a/src/Accounts/Account.php +++ b/src/Accounts/Account.php @@ -30,13 +30,13 @@ final class Account implements BaseModel use SdkModel; /** - * Chat account added to Beeper. Use this to route account-scoped actions. + * Chat account added to Beeper. Use this to route account-scoped actions. Examples include matrix for Beeper/Matrix, discordgo for a cloud bridge, slackgo.TEAM-USER for workspace-scoped cloud bridges, and local-whatsapp_ba_... for local bridges. */ #[Required] public string $accountID; /** - * Bridge metadata for the account. Available in Beeper Desktop v4.2.799+. + * Bridge metadata for the account. Available in Beeper Desktop v4.2.785+. */ #[Required] public Bridge $bridge; @@ -98,7 +98,7 @@ public static function with( } /** - * Chat account added to Beeper. Use this to route account-scoped actions. + * Chat account added to Beeper. Use this to route account-scoped actions. Examples include matrix for Beeper/Matrix, discordgo for a cloud bridge, slackgo.TEAM-USER for workspace-scoped cloud bridges, and local-whatsapp_ba_... for local bridges. */ public function withAccountID(string $accountID): self { @@ -109,7 +109,7 @@ public function withAccountID(string $accountID): self } /** - * Bridge metadata for the account. Available in Beeper Desktop v4.2.799+. + * Bridge metadata for the account. Available in Beeper Desktop v4.2.785+. * * @param Bridge|BridgeShape $bridge */ diff --git a/src/Accounts/Account/Bridge.php b/src/Accounts/Account/Bridge.php index 1283c52..5651fc8 100644 --- a/src/Accounts/Account/Bridge.php +++ b/src/Accounts/Account/Bridge.php @@ -10,7 +10,7 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** - * Bridge metadata for the account. Available in Beeper Desktop v4.2.799+. + * Bridge metadata for the account. Available in Beeper Desktop v4.2.785+. * * @phpstan-type BridgeShape = array{ * id: string, provider: Provider|value-of, type: string @@ -22,13 +22,13 @@ final class Bridge implements BaseModel use SdkModel; /** - * Bridge instance identifier. Available in Beeper Desktop v4.2.799+. + * 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+. */ #[Required] public string $id; /** - * Bridge provider for the account. Available in Beeper Desktop v4.2.799+. + * Bridge provider for the account. Available in Beeper Desktop v4.2.785+. * * @var value-of $provider */ @@ -36,7 +36,7 @@ final class Bridge implements BaseModel public string $provider; /** - * Bridge type. Available in Beeper Desktop v4.2.799+. + * Bridge type, such as matrix, discordgo, slackgo, whatsapp, telegram, or twitter. Available in Beeper Desktop v4.2.785+. */ #[Required] public string $type; @@ -82,7 +82,7 @@ public static function with( } /** - * Bridge instance identifier. Available in Beeper Desktop v4.2.799+. + * 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+. */ public function withID(string $id): self { @@ -93,7 +93,7 @@ public function withID(string $id): self } /** - * Bridge provider for the account. Available in Beeper Desktop v4.2.799+. + * Bridge provider for the account. Available in Beeper Desktop v4.2.785+. * * @param Provider|value-of $provider */ @@ -106,7 +106,7 @@ public function withProvider(Provider|string $provider): self } /** - * Bridge type. Available in Beeper Desktop v4.2.799+. + * Bridge type, such as matrix, discordgo, slackgo, whatsapp, telegram, or twitter. Available in Beeper Desktop v4.2.785+. */ public function withType(string $type): self { diff --git a/src/Accounts/Account/Bridge/Provider.php b/src/Accounts/Account/Bridge/Provider.php index 9a0fa83..e8a0591 100644 --- a/src/Accounts/Account/Bridge/Provider.php +++ b/src/Accounts/Account/Bridge/Provider.php @@ -5,7 +5,7 @@ namespace BeeperDesktop\Accounts\Account\Bridge; /** - * Bridge provider for the account. Available in Beeper Desktop v4.2.799+. + * Bridge provider for the account. Available in Beeper Desktop v4.2.785+. */ enum Provider: string { diff --git a/src/Assets/AssetDownloadParams.php b/src/Assets/AssetDownloadParams.php index aff13d1..51fec2d 100644 --- a/src/Assets/AssetDownloadParams.php +++ b/src/Assets/AssetDownloadParams.php @@ -10,7 +10,7 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** - * Download a Matrix asset using its mxc:// or localmxc:// URL to the device running Beeper Desktop and return the local file URL. + * Download a Matrix file using its mxc:// or localmxc:// URL to the device running Beeper Desktop and return the local file URL. * * @see BeeperDesktop\Services\AssetsService::download() * @@ -23,7 +23,7 @@ final class AssetDownloadParams implements BaseModel use SdkParams; /** - * Matrix content URL (mxc:// or localmxc://) for the asset to download. + * Matrix content URL (mxc:// or localmxc://) for the file to download. */ #[Required] public string $url; @@ -62,7 +62,7 @@ public static function with(string $url): self } /** - * Matrix content URL (mxc:// or localmxc://) for the asset to download. + * Matrix content URL (mxc:// or localmxc://) for the file to download. */ public function withURL(string $url): self { diff --git a/src/Assets/AssetDownloadResponse.php b/src/Assets/AssetDownloadResponse.php index 3252eff..672dd84 100644 --- a/src/Assets/AssetDownloadResponse.php +++ b/src/Assets/AssetDownloadResponse.php @@ -25,7 +25,7 @@ final class AssetDownloadResponse implements BaseModel public ?string $error; /** - * Local file URL to the downloaded asset. + * Local file URL to the downloaded file. */ #[Optional] public ?string $srcURL; @@ -64,7 +64,7 @@ public function withError(string $error): self } /** - * Local file URL to the downloaded asset. + * Local file URL to the downloaded file. */ public function withSrcURL(string $srcURL): self { diff --git a/src/Assets/AssetServeParams.php b/src/Assets/AssetServeParams.php index 160f4cc..67444b2 100644 --- a/src/Assets/AssetServeParams.php +++ b/src/Assets/AssetServeParams.php @@ -23,7 +23,7 @@ final class AssetServeParams implements BaseModel use SdkParams; /** - * Asset URL to serve. Accepts mxc://, localmxc://, or file:// URLs. + * File URL to serve. Accepts mxc://, localmxc://, or file:// URLs. */ #[Required] public string $url; @@ -62,7 +62,7 @@ public static function with(string $url): self } /** - * Asset URL to serve. Accepts mxc://, localmxc://, or file:// URLs. + * File URL to serve. Accepts mxc://, localmxc://, or file:// URLs. */ public function withURL(string $url): self { diff --git a/src/Assets/AssetUploadBase64Params.php b/src/Assets/AssetUploadBase64Params.php index f1772cf..b3b9328 100644 --- a/src/Assets/AssetUploadBase64Params.php +++ b/src/Assets/AssetUploadBase64Params.php @@ -11,7 +11,7 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** - * Upload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending messages with attachments. Alternative to the multipart upload endpoint. + * Upload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment. Alternative to the multipart upload endpoint. * * @see BeeperDesktop\Services\AssetsService::uploadBase64() * diff --git a/src/Assets/AssetUploadBase64Response.php b/src/Assets/AssetUploadBase64Response.php index dc6e76b..61bd641 100644 --- a/src/Assets/AssetUploadBase64Response.php +++ b/src/Assets/AssetUploadBase64Response.php @@ -63,13 +63,13 @@ final class AssetUploadBase64Response implements BaseModel public ?string $mimeType; /** - * Local file URL (file://) for the uploaded asset. + * Local file URL (file://) for the uploaded file. */ #[Optional] public ?string $srcURL; /** - * Unique upload ID for this asset. + * Unique upload ID for this temporary file. */ #[Optional] public ?string $uploadID; @@ -183,7 +183,7 @@ public function withMimeType(string $mimeType): self } /** - * Local file URL (file://) for the uploaded asset. + * Local file URL (file://) for the uploaded file. */ public function withSrcURL(string $srcURL): self { @@ -194,7 +194,7 @@ public function withSrcURL(string $srcURL): self } /** - * Unique upload ID for this asset. + * Unique upload ID for this temporary file. */ public function withUploadID(string $uploadID): self { diff --git a/src/Assets/AssetUploadParams.php b/src/Assets/AssetUploadParams.php index 1d4b690..5d25f3b 100644 --- a/src/Assets/AssetUploadParams.php +++ b/src/Assets/AssetUploadParams.php @@ -12,7 +12,7 @@ use BeeperDesktop\Core\FileParam; /** - * Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending messages with attachments. + * Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment. * * @see BeeperDesktop\Services\AssetsService::upload() * diff --git a/src/Assets/AssetUploadResponse.php b/src/Assets/AssetUploadResponse.php index 267aa80..7ef0f69 100644 --- a/src/Assets/AssetUploadResponse.php +++ b/src/Assets/AssetUploadResponse.php @@ -63,13 +63,13 @@ final class AssetUploadResponse implements BaseModel public ?string $mimeType; /** - * Local file URL (file://) for the uploaded asset. + * Local file URL (file://) for the uploaded file. */ #[Optional] public ?string $srcURL; /** - * Unique upload ID for this asset. + * Unique upload ID for this temporary file. */ #[Optional] public ?string $uploadID; @@ -183,7 +183,7 @@ public function withMimeType(string $mimeType): self } /** - * Local file URL (file://) for the uploaded asset. + * Local file URL (file://) for the uploaded file. */ public function withSrcURL(string $srcURL): self { @@ -194,7 +194,7 @@ public function withSrcURL(string $srcURL): self } /** - * Unique upload ID for this asset. + * Unique upload ID for this temporary file. */ public function withUploadID(string $uploadID): self { diff --git a/src/Attachment.php b/src/Attachment.php index 0330436..1c12d82 100644 --- a/src/Attachment.php +++ b/src/Attachment.php @@ -5,6 +5,7 @@ namespace BeeperDesktop; use BeeperDesktop\Attachment\Size; +use BeeperDesktop\Attachment\Transcription; use BeeperDesktop\Attachment\Type; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Attributes\Required; @@ -13,6 +14,7 @@ /** * @phpstan-import-type SizeShape from \BeeperDesktop\Attachment\Size + * @phpstan-import-type TranscriptionShape from \BeeperDesktop\Attachment\Transcription * * @phpstan-type AttachmentShape = array{ * type: Type|value-of, @@ -27,6 +29,7 @@ * posterImg?: string|null, * size?: null|Size|SizeShape, * srcURL?: string|null, + * transcription?: null|Transcription|TranscriptionShape, * } */ final class Attachment implements BaseModel @@ -43,7 +46,7 @@ final class Attachment implements BaseModel public string $type; /** - * Attachment identifier (typically an mxc:// URL). Use with /v1/assets/download to get a local file path. + * Attachment identifier (typically an mxc:// URL). Use the download file endpoint to get a local file path. */ #[Optional] public ?string $id; @@ -103,11 +106,17 @@ final class Attachment implements BaseModel public ?Size $size; /** - * Public URL or local file path to fetch the asset. May be temporary or local-only to this device; download promptly if durable access is needed. + * Public URL or local file path to fetch the file. May be temporary or local-only to this device; download promptly if durable access is needed. */ #[Optional] public ?string $srcURL; + /** + * Attachment transcription if available. + */ + #[Optional] + public ?Transcription $transcription; + /** * `new Attachment()` is missing required properties by the API. * @@ -134,6 +143,7 @@ public function __construct() * * @param Type|value-of $type * @param Size|SizeShape|null $size + * @param Transcription|TranscriptionShape|null $transcription */ public static function with( Type|string $type, @@ -148,6 +158,7 @@ public static function with( ?string $posterImg = null, Size|array|null $size = null, ?string $srcURL = null, + Transcription|array|null $transcription = null, ): self { $self = new self; @@ -164,6 +175,7 @@ public static function with( null !== $posterImg && $self['posterImg'] = $posterImg; null !== $size && $self['size'] = $size; null !== $srcURL && $self['srcURL'] = $srcURL; + null !== $transcription && $self['transcription'] = $transcription; return $self; } @@ -182,7 +194,7 @@ public function withType(Type|string $type): self } /** - * Attachment identifier (typically an mxc:// URL). Use with /v1/assets/download to get a local file path. + * Attachment identifier (typically an mxc:// URL). Use the download file endpoint to get a local file path. */ public function withID(string $id): self { @@ -294,7 +306,7 @@ public function withSize(Size|array $size): self } /** - * Public URL or local file path to fetch the asset. May be temporary or local-only to this device; download promptly if durable access is needed. + * Public URL or local file path to fetch the file. May be temporary or local-only to this device; download promptly if durable access is needed. */ public function withSrcURL(string $srcURL): self { @@ -303,4 +315,17 @@ public function withSrcURL(string $srcURL): self return $self; } + + /** + * Attachment transcription if available. + * + * @param Transcription|TranscriptionShape $transcription + */ + public function withTranscription(Transcription|array $transcription): self + { + $self = clone $this; + $self['transcription'] = $transcription; + + return $self; + } } diff --git a/src/Attachment/Transcription.php b/src/Attachment/Transcription.php new file mode 100644 index 0000000..957c2d5 --- /dev/null +++ b/src/Attachment/Transcription.php @@ -0,0 +1,113 @@ + */ + use SdkModel; + + /** + * Transcription engine. + */ + #[Required] + public string $engine; + + /** + * Transcribed text. + */ + #[Required] + public string $transcription; + + /** + * Detected or selected language. + */ + #[Optional] + public ?string $language; + + /** + * `new Transcription()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Transcription::with(engine: ..., transcription: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Transcription)->withEngine(...)->withTranscription(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $engine, + string $transcription, + ?string $language = null + ): self { + $self = new self; + + $self['engine'] = $engine; + $self['transcription'] = $transcription; + + null !== $language && $self['language'] = $language; + + return $self; + } + + /** + * Transcription engine. + */ + public function withEngine(string $engine): self + { + $self = clone $this; + $self['engine'] = $engine; + + return $self; + } + + /** + * Transcribed text. + */ + public function withTranscription(string $transcription): self + { + $self = clone $this; + $self['transcription'] = $transcription; + + return $self; + } + + /** + * Detected or selected language. + */ + public function withLanguage(string $language): self + { + $self = clone $this; + $self['language'] = $language; + + return $self; + } +} diff --git a/src/BeeperDesktopFocusParams.php b/src/BeeperDesktopFocusParams.php index 94b8844..7aa7429 100644 --- a/src/BeeperDesktopFocusParams.php +++ b/src/BeeperDesktopFocusParams.php @@ -10,7 +10,7 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** - * Focus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill draft text and attachment. + * Focus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill plain text and an image path. * * @see BeeperDesktop\Services\BeeperDesktopClientService::focus() * @@ -34,13 +34,13 @@ final class BeeperDesktopFocusParams implements BaseModel public ?string $chatID; /** - * Optional draft attachment path to populate in the message input field. + * Optional image path to populate in the message input field. */ #[Optional] public ?string $draftAttachmentPath; /** - * Optional draft text to populate in the message input field. + * Optional plain text to populate in the message input field. */ #[Optional] public ?string $draftText; @@ -89,7 +89,7 @@ public function withChatID(string $chatID): self } /** - * Optional draft attachment path to populate in the message input field. + * Optional image path to populate in the message input field. */ public function withDraftAttachmentPath(string $draftAttachmentPath): self { @@ -100,7 +100,7 @@ public function withDraftAttachmentPath(string $draftAttachmentPath): self } /** - * Optional draft text to populate in the message input field. + * Optional plain text to populate in the message input field. */ public function withDraftText(string $draftText): self { diff --git a/src/Chats/Chat.php b/src/Chats/Chat.php index 8beb567..fbaa5e9 100644 --- a/src/Chats/Chat.php +++ b/src/Chats/Chat.php @@ -4,7 +4,11 @@ namespace BeeperDesktop\Chats; +use BeeperDesktop\Chats\Chat\Capabilities; +use BeeperDesktop\Chats\Chat\Draft; use BeeperDesktop\Chats\Chat\Participants; +use BeeperDesktop\Chats\Chat\Reminder; +use BeeperDesktop\Chats\Chat\Snooze; use BeeperDesktop\Chats\Chat\Type; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Attributes\Required; @@ -13,20 +17,36 @@ /** * @phpstan-import-type ParticipantsShape from \BeeperDesktop\Chats\Chat\Participants + * @phpstan-import-type CapabilitiesShape from \BeeperDesktop\Chats\Chat\Capabilities + * @phpstan-import-type DraftShape from \BeeperDesktop\Chats\Chat\Draft + * @phpstan-import-type ReminderShape from \BeeperDesktop\Chats\Chat\Reminder + * @phpstan-import-type SnoozeShape from \BeeperDesktop\Chats\Chat\Snooze * * @phpstan-type ChatShape = array{ * id: string, * accountID: string, + * network: string, * participants: Participants|ParticipantsShape, * title: string, * type: Type|value-of, * unreadCount: int, + * capabilities?: null|Capabilities|CapabilitiesShape, + * description?: string|null, + * draft?: null|Draft|DraftShape, + * imgURL?: string|null, * isArchived?: bool|null, + * isLowPriority?: bool|null, + * isMarkedUnread?: bool|null, * isMuted?: bool|null, * isPinned?: bool|null, + * isReadOnly?: bool|null, * lastActivity?: \DateTimeInterface|null, * lastReadMessageSortKey?: string|null, * localChatID?: string|null, + * messageExpirySeconds?: int|null, + * reminder?: null|Reminder|ReminderShape, + * snooze?: null|Snooze|SnoozeShape, + * unreadMentionsCount?: int|null, * } */ final class Chat implements BaseModel @@ -46,6 +66,12 @@ final class Chat implements BaseModel #[Required] public string $accountID; + /** + * Display-only human-readable account/network name. + */ + #[Required] + public string $network; + /** * Chat participants information. */ @@ -72,12 +98,48 @@ final class Chat implements BaseModel #[Required] public int $unreadCount; + /** + * Chat capabilities reported by the platform. + */ + #[Optional] + public ?Capabilities $capabilities; + + /** + * Group chat description/topic when available. + */ + #[Optional(nullable: true)] + public ?string $description; + + /** + * Current draft object for this chat, or null when no draft is set. + */ + #[Optional(nullable: true)] + public ?Draft $draft; + + /** + * Local filesystem path to the chat avatar image when available. + */ + #[Optional(nullable: true)] + public ?string $imgURL; + /** * True if chat is archived. */ #[Optional] public ?bool $isArchived; + /** + * True if chat is marked low priority. + */ + #[Optional] + public ?bool $isLowPriority; + + /** + * True if the chat was explicitly marked unread by the authenticated user. + */ + #[Optional] + public ?bool $isMarkedUnread; + /** * True if chat notifications are muted. */ @@ -90,6 +152,12 @@ final class Chat implements BaseModel #[Optional] public ?bool $isPinned; + /** + * True if messages cannot be sent in this chat. + */ + #[Optional] + public ?bool $isReadOnly; + /** * Timestamp of last activity. */ @@ -108,6 +176,30 @@ final class Chat implements BaseModel #[Optional(nullable: true)] public ?string $localChatID; + /** + * Disappearing-message timer in seconds when available. + */ + #[Optional(nullable: true)] + public ?int $messageExpirySeconds; + + /** + * Current reminder for this chat, or null when no reminder is set. + */ + #[Optional(nullable: true)] + public ?Reminder $reminder; + + /** + * Current snooze state for this chat, or null when no snooze is set. + */ + #[Optional(nullable: true)] + public ?Snooze $snooze; + + /** + * Number of unread messages that mention the authenticated user or @room. + */ + #[Optional] + public ?int $unreadMentionsCount; + /** * `new Chat()` is missing required properties by the API. * @@ -116,6 +208,7 @@ final class Chat implements BaseModel * Chat::with( * id: ..., * accountID: ..., + * network: ..., * participants: ..., * title: ..., * type: ..., @@ -129,6 +222,7 @@ final class Chat implements BaseModel * (new Chat) * ->withID(...) * ->withAccountID(...) + * ->withNetwork(...) * ->withParticipants(...) * ->withTitle(...) * ->withType(...) @@ -147,36 +241,64 @@ public function __construct() * * @param Participants|ParticipantsShape $participants * @param Type|value-of $type + * @param Capabilities|CapabilitiesShape|null $capabilities + * @param Draft|DraftShape|null $draft + * @param Reminder|ReminderShape|null $reminder + * @param Snooze|SnoozeShape|null $snooze */ public static function with( string $id, string $accountID, + string $network, Participants|array $participants, string $title, Type|string $type, int $unreadCount, + Capabilities|array|null $capabilities = null, + ?string $description = null, + Draft|array|null $draft = null, + ?string $imgURL = null, ?bool $isArchived = null, + ?bool $isLowPriority = null, + ?bool $isMarkedUnread = null, ?bool $isMuted = null, ?bool $isPinned = null, + ?bool $isReadOnly = null, ?\DateTimeInterface $lastActivity = null, ?string $lastReadMessageSortKey = null, ?string $localChatID = null, + ?int $messageExpirySeconds = null, + Reminder|array|null $reminder = null, + Snooze|array|null $snooze = null, + ?int $unreadMentionsCount = null, ): self { $self = new self; $self['id'] = $id; $self['accountID'] = $accountID; + $self['network'] = $network; $self['participants'] = $participants; $self['title'] = $title; $self['type'] = $type; $self['unreadCount'] = $unreadCount; + null !== $capabilities && $self['capabilities'] = $capabilities; + null !== $description && $self['description'] = $description; + null !== $draft && $self['draft'] = $draft; + null !== $imgURL && $self['imgURL'] = $imgURL; null !== $isArchived && $self['isArchived'] = $isArchived; + null !== $isLowPriority && $self['isLowPriority'] = $isLowPriority; + null !== $isMarkedUnread && $self['isMarkedUnread'] = $isMarkedUnread; null !== $isMuted && $self['isMuted'] = $isMuted; null !== $isPinned && $self['isPinned'] = $isPinned; + null !== $isReadOnly && $self['isReadOnly'] = $isReadOnly; null !== $lastActivity && $self['lastActivity'] = $lastActivity; null !== $lastReadMessageSortKey && $self['lastReadMessageSortKey'] = $lastReadMessageSortKey; null !== $localChatID && $self['localChatID'] = $localChatID; + null !== $messageExpirySeconds && $self['messageExpirySeconds'] = $messageExpirySeconds; + null !== $reminder && $self['reminder'] = $reminder; + null !== $snooze && $self['snooze'] = $snooze; + null !== $unreadMentionsCount && $self['unreadMentionsCount'] = $unreadMentionsCount; return $self; } @@ -203,6 +325,17 @@ public function withAccountID(string $accountID): self return $self; } + /** + * Display-only human-readable account/network name. + */ + public function withNetwork(string $network): self + { + $self = clone $this; + $self['network'] = $network; + + return $self; + } + /** * Chat participants information. * @@ -251,6 +384,54 @@ public function withUnreadCount(int $unreadCount): self return $self; } + /** + * Chat capabilities reported by the platform. + * + * @param Capabilities|CapabilitiesShape $capabilities + */ + public function withCapabilities(Capabilities|array $capabilities): self + { + $self = clone $this; + $self['capabilities'] = $capabilities; + + return $self; + } + + /** + * Group chat description/topic when available. + */ + public function withDescription(?string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * Current draft object for this chat, or null when no draft is set. + * + * @param Draft|DraftShape|null $draft + */ + public function withDraft(Draft|array|null $draft): self + { + $self = clone $this; + $self['draft'] = $draft; + + return $self; + } + + /** + * Local filesystem path to the chat avatar image when available. + */ + public function withImgURL(?string $imgURL): self + { + $self = clone $this; + $self['imgURL'] = $imgURL; + + return $self; + } + /** * True if chat is archived. */ @@ -262,6 +443,28 @@ public function withIsArchived(bool $isArchived): self return $self; } + /** + * True if chat is marked low priority. + */ + public function withIsLowPriority(bool $isLowPriority): self + { + $self = clone $this; + $self['isLowPriority'] = $isLowPriority; + + return $self; + } + + /** + * True if the chat was explicitly marked unread by the authenticated user. + */ + public function withIsMarkedUnread(bool $isMarkedUnread): self + { + $self = clone $this; + $self['isMarkedUnread'] = $isMarkedUnread; + + return $self; + } + /** * True if chat notifications are muted. */ @@ -284,6 +487,17 @@ public function withIsPinned(bool $isPinned): self return $self; } + /** + * True if messages cannot be sent in this chat. + */ + public function withIsReadOnly(bool $isReadOnly): self + { + $self = clone $this; + $self['isReadOnly'] = $isReadOnly; + + return $self; + } + /** * Timestamp of last activity. */ @@ -317,4 +531,52 @@ public function withLocalChatID(?string $localChatID): self return $self; } + + /** + * Disappearing-message timer in seconds when available. + */ + public function withMessageExpirySeconds(?int $messageExpirySeconds): self + { + $self = clone $this; + $self['messageExpirySeconds'] = $messageExpirySeconds; + + return $self; + } + + /** + * Current reminder for this chat, or null when no reminder is set. + * + * @param Reminder|ReminderShape|null $reminder + */ + public function withReminder(Reminder|array|null $reminder): self + { + $self = clone $this; + $self['reminder'] = $reminder; + + return $self; + } + + /** + * Current snooze state for this chat, or null when no snooze is set. + * + * @param Snooze|SnoozeShape|null $snooze + */ + public function withSnooze(Snooze|array|null $snooze): self + { + $self = clone $this; + $self['snooze'] = $snooze; + + return $self; + } + + /** + * Number of unread messages that mention the authenticated user or @room. + */ + public function withUnreadMentionsCount(int $unreadMentionsCount): self + { + $self = clone $this; + $self['unreadMentionsCount'] = $unreadMentionsCount; + + return $self; + } } diff --git a/src/Chats/Chat/Capabilities.php b/src/Chats/Chat/Capabilities.php new file mode 100644 index 0000000..d60c40a --- /dev/null +++ b/src/Chats/Chat/Capabilities.php @@ -0,0 +1,665 @@ +|null, + * archive?: bool|null, + * attachments?: array|null, + * customEmojiReactions?: bool|null, + * delete?: null|Delete|value-of, + * deleteChat?: bool|null, + * deleteChatForEveryone?: bool|null, + * deleteForMe?: bool|null, + * deleteMaxAge?: int|null, + * disappearingTimer?: null|DisappearingTimer|DisappearingTimerShape, + * edit?: null|Edit|value-of, + * editMaxAge?: int|null, + * editMaxCount?: int|null, + * formatting?: array>|null, + * locationMessage?: null|LocationMessage|value-of, + * markAsUnread?: bool|null, + * maxTextLength?: int|null, + * messageRequest?: null|MessageRequest|MessageRequestShape, + * participantActions?: null|ParticipantActions|ParticipantActionsShape, + * poll?: null|Poll|value-of, + * reaction?: null|Reaction|value-of, + * reactionCount?: int|null, + * readReceipts?: bool|null, + * reply?: null|Reply|value-of, + * state?: null|State|StateShape, + * thread?: null|Thread|value-of, + * typingNotifications?: bool|null, + * } + */ +final class Capabilities implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Allowed Unicode reactions. Omitted means all emoji reactions are allowed. + * + * @var list|null $allowedReactions + */ + #[Optional(list: 'string')] + public ?array $allowedReactions; + + /** + * True if archive/unarchive is supported. + */ + #[Optional] + public ?bool $archive; + + /** + * Supported attachment message types and their per-type constraints, keyed by Matrix msgtype or pseudo-msgtype (for example m.image, m.video, org.matrix.msc3245.voice). Missing message types should be treated as rejected. + * + * @var array|null $attachments + */ + #[Optional(map: Attachment::class)] + public ?array $attachments; + + /** + * True if custom emoji reactions are supported. + */ + #[Optional] + public ?bool $customEmojiReactions; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $delete + */ + #[Optional(enum: Delete::class)] + public ?int $delete; + + /** + * True if deleting chats for the authenticated user is supported. + */ + #[Optional] + public ?bool $deleteChat; + + /** + * True if deleting chats for everyone is supported. + */ + #[Optional] + public ?bool $deleteChatForEveryone; + + /** + * True if deleting messages only for the authenticated user is supported. + */ + #[Optional] + public ?bool $deleteForMe; + + /** + * Maximum message age for delete-for-everyone, in seconds. + */ + #[Optional] + public ?int $deleteMaxAge; + + /** + * Disappearing-message timer capabilities. + */ + #[Optional] + public ?DisappearingTimer $disappearingTimer; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $edit + */ + #[Optional(enum: Edit::class)] + public ?int $edit; + + /** + * Maximum message age for edits, in seconds. + */ + #[Optional] + public ?int $editMaxAge; + + /** + * Maximum number of edits allowed for one message. + */ + #[Optional] + public ?int $editMaxCount; + + /** + * Supported rich-text formatting features keyed by feature name (for example bold, inline_code, code_block.syntax_highlighting). Omitted means no formatting support is advertised. + * + * @var array>|null $formatting + */ + #[Optional(map: Formatting::class)] + public ?array $formatting; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $locationMessage + */ + #[Optional(enum: LocationMessage::class)] + public ?int $locationMessage; + + /** + * True if marking chats unread is supported. + */ + #[Optional] + public ?bool $markAsUnread; + + /** + * Maximum length of normal text messages. + */ + #[Optional] + public ?int $maxTextLength; + + /** + * Message request capabilities. + */ + #[Optional] + public ?MessageRequest $messageRequest; + + /** + * Participant management capabilities. + */ + #[Optional] + public ?ParticipantActions $participantActions; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $poll + */ + #[Optional(enum: Poll::class)] + public ?int $poll; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $reaction + */ + #[Optional(enum: Reaction::class)] + public ?int $reaction; + + /** + * Maximum number of reactions allowed on a single message. + */ + #[Optional] + public ?int $reactionCount; + + /** + * True if read receipts are supported. + */ + #[Optional] + public ?bool $readReceipts; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $reply + */ + #[Optional(enum: Reply::class)] + public ?int $reply; + + /** + * Chat state update capabilities. + */ + #[Optional] + public ?State $state; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $thread + */ + #[Optional(enum: Thread::class)] + public ?int $thread; + + /** + * True if typing notifications are supported. + */ + #[Optional] + public ?bool $typingNotifications; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list|null $allowedReactions + * @param array|null $attachments + * @param Delete|value-of|null $delete + * @param DisappearingTimer|DisappearingTimerShape|null $disappearingTimer + * @param Edit|value-of|null $edit + * @param array>|null $formatting + * @param LocationMessage|value-of|null $locationMessage + * @param MessageRequest|MessageRequestShape|null $messageRequest + * @param ParticipantActions|ParticipantActionsShape|null $participantActions + * @param Poll|value-of|null $poll + * @param Reaction|value-of|null $reaction + * @param Reply|value-of|null $reply + * @param State|StateShape|null $state + * @param Thread|value-of|null $thread + */ + public static function with( + ?array $allowedReactions = null, + ?bool $archive = null, + ?array $attachments = null, + ?bool $customEmojiReactions = null, + Delete|int|null $delete = null, + ?bool $deleteChat = null, + ?bool $deleteChatForEveryone = null, + ?bool $deleteForMe = null, + ?int $deleteMaxAge = null, + DisappearingTimer|array|null $disappearingTimer = null, + Edit|int|null $edit = null, + ?int $editMaxAge = null, + ?int $editMaxCount = null, + ?array $formatting = null, + LocationMessage|int|null $locationMessage = null, + ?bool $markAsUnread = null, + ?int $maxTextLength = null, + MessageRequest|array|null $messageRequest = null, + ParticipantActions|array|null $participantActions = null, + Poll|int|null $poll = null, + Reaction|int|null $reaction = null, + ?int $reactionCount = null, + ?bool $readReceipts = null, + Reply|int|null $reply = null, + State|array|null $state = null, + Thread|int|null $thread = null, + ?bool $typingNotifications = null, + ): self { + $self = new self; + + null !== $allowedReactions && $self['allowedReactions'] = $allowedReactions; + null !== $archive && $self['archive'] = $archive; + null !== $attachments && $self['attachments'] = $attachments; + null !== $customEmojiReactions && $self['customEmojiReactions'] = $customEmojiReactions; + null !== $delete && $self['delete'] = $delete; + null !== $deleteChat && $self['deleteChat'] = $deleteChat; + null !== $deleteChatForEveryone && $self['deleteChatForEveryone'] = $deleteChatForEveryone; + null !== $deleteForMe && $self['deleteForMe'] = $deleteForMe; + null !== $deleteMaxAge && $self['deleteMaxAge'] = $deleteMaxAge; + null !== $disappearingTimer && $self['disappearingTimer'] = $disappearingTimer; + null !== $edit && $self['edit'] = $edit; + null !== $editMaxAge && $self['editMaxAge'] = $editMaxAge; + null !== $editMaxCount && $self['editMaxCount'] = $editMaxCount; + null !== $formatting && $self['formatting'] = $formatting; + null !== $locationMessage && $self['locationMessage'] = $locationMessage; + null !== $markAsUnread && $self['markAsUnread'] = $markAsUnread; + null !== $maxTextLength && $self['maxTextLength'] = $maxTextLength; + null !== $messageRequest && $self['messageRequest'] = $messageRequest; + null !== $participantActions && $self['participantActions'] = $participantActions; + null !== $poll && $self['poll'] = $poll; + null !== $reaction && $self['reaction'] = $reaction; + null !== $reactionCount && $self['reactionCount'] = $reactionCount; + null !== $readReceipts && $self['readReceipts'] = $readReceipts; + null !== $reply && $self['reply'] = $reply; + null !== $state && $self['state'] = $state; + null !== $thread && $self['thread'] = $thread; + null !== $typingNotifications && $self['typingNotifications'] = $typingNotifications; + + return $self; + } + + /** + * Allowed Unicode reactions. Omitted means all emoji reactions are allowed. + * + * @param list $allowedReactions + */ + public function withAllowedReactions(array $allowedReactions): self + { + $self = clone $this; + $self['allowedReactions'] = $allowedReactions; + + return $self; + } + + /** + * True if archive/unarchive is supported. + */ + public function withArchive(bool $archive): self + { + $self = clone $this; + $self['archive'] = $archive; + + return $self; + } + + /** + * Supported attachment message types and their per-type constraints, keyed by Matrix msgtype or pseudo-msgtype (for example m.image, m.video, org.matrix.msc3245.voice). Missing message types should be treated as rejected. + * + * @param array $attachments + */ + public function withAttachments(array $attachments): self + { + $self = clone $this; + $self['attachments'] = $attachments; + + return $self; + } + + /** + * True if custom emoji reactions are supported. + */ + public function withCustomEmojiReactions(bool $customEmojiReactions): self + { + $self = clone $this; + $self['customEmojiReactions'] = $customEmojiReactions; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Delete|value-of $delete + */ + public function withDelete(Delete|int $delete): self + { + $self = clone $this; + $self['delete'] = $delete; + + return $self; + } + + /** + * True if deleting chats for the authenticated user is supported. + */ + public function withDeleteChat(bool $deleteChat): self + { + $self = clone $this; + $self['deleteChat'] = $deleteChat; + + return $self; + } + + /** + * True if deleting chats for everyone is supported. + */ + public function withDeleteChatForEveryone(bool $deleteChatForEveryone): self + { + $self = clone $this; + $self['deleteChatForEveryone'] = $deleteChatForEveryone; + + return $self; + } + + /** + * True if deleting messages only for the authenticated user is supported. + */ + public function withDeleteForMe(bool $deleteForMe): self + { + $self = clone $this; + $self['deleteForMe'] = $deleteForMe; + + return $self; + } + + /** + * Maximum message age for delete-for-everyone, in seconds. + */ + public function withDeleteMaxAge(int $deleteMaxAge): self + { + $self = clone $this; + $self['deleteMaxAge'] = $deleteMaxAge; + + return $self; + } + + /** + * Disappearing-message timer capabilities. + * + * @param DisappearingTimer|DisappearingTimerShape $disappearingTimer + */ + public function withDisappearingTimer( + DisappearingTimer|array $disappearingTimer + ): self { + $self = clone $this; + $self['disappearingTimer'] = $disappearingTimer; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Edit|value-of $edit + */ + public function withEdit(Edit|int $edit): self + { + $self = clone $this; + $self['edit'] = $edit; + + return $self; + } + + /** + * Maximum message age for edits, in seconds. + */ + public function withEditMaxAge(int $editMaxAge): self + { + $self = clone $this; + $self['editMaxAge'] = $editMaxAge; + + return $self; + } + + /** + * Maximum number of edits allowed for one message. + */ + public function withEditMaxCount(int $editMaxCount): self + { + $self = clone $this; + $self['editMaxCount'] = $editMaxCount; + + return $self; + } + + /** + * Supported rich-text formatting features keyed by feature name (for example bold, inline_code, code_block.syntax_highlighting). Omitted means no formatting support is advertised. + * + * @param array> $formatting + */ + public function withFormatting(array $formatting): self + { + $self = clone $this; + $self['formatting'] = $formatting; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param LocationMessage|value-of $locationMessage + */ + public function withLocationMessage( + LocationMessage|int $locationMessage + ): self { + $self = clone $this; + $self['locationMessage'] = $locationMessage; + + return $self; + } + + /** + * True if marking chats unread is supported. + */ + public function withMarkAsUnread(bool $markAsUnread): self + { + $self = clone $this; + $self['markAsUnread'] = $markAsUnread; + + return $self; + } + + /** + * Maximum length of normal text messages. + */ + public function withMaxTextLength(int $maxTextLength): self + { + $self = clone $this; + $self['maxTextLength'] = $maxTextLength; + + return $self; + } + + /** + * Message request capabilities. + * + * @param MessageRequest|MessageRequestShape $messageRequest + */ + public function withMessageRequest( + MessageRequest|array $messageRequest + ): self { + $self = clone $this; + $self['messageRequest'] = $messageRequest; + + return $self; + } + + /** + * Participant management capabilities. + * + * @param ParticipantActions|ParticipantActionsShape $participantActions + */ + public function withParticipantActions( + ParticipantActions|array $participantActions + ): self { + $self = clone $this; + $self['participantActions'] = $participantActions; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Poll|value-of $poll + */ + public function withPoll(Poll|int $poll): self + { + $self = clone $this; + $self['poll'] = $poll; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Reaction|value-of $reaction + */ + public function withReaction(Reaction|int $reaction): self + { + $self = clone $this; + $self['reaction'] = $reaction; + + return $self; + } + + /** + * Maximum number of reactions allowed on a single message. + */ + public function withReactionCount(int $reactionCount): self + { + $self = clone $this; + $self['reactionCount'] = $reactionCount; + + return $self; + } + + /** + * True if read receipts are supported. + */ + public function withReadReceipts(bool $readReceipts): self + { + $self = clone $this; + $self['readReceipts'] = $readReceipts; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Reply|value-of $reply + */ + public function withReply(Reply|int $reply): self + { + $self = clone $this; + $self['reply'] = $reply; + + return $self; + } + + /** + * Chat state update capabilities. + * + * @param State|StateShape $state + */ + public function withState(State|array $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Thread|value-of $thread + */ + public function withThread(Thread|int $thread): self + { + $self = clone $this; + $self['thread'] = $thread; + + return $self; + } + + /** + * True if typing notifications are supported. + */ + public function withTypingNotifications(bool $typingNotifications): self + { + $self = clone $this; + $self['typingNotifications'] = $typingNotifications; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/Attachment.php b/src/Chats/Chat/Capabilities/Attachment.php new file mode 100644 index 0000000..a6d3426 --- /dev/null +++ b/src/Chats/Chat/Capabilities/Attachment.php @@ -0,0 +1,228 @@ +>, + * caption?: null|Caption|value-of, + * maxCaptionLength?: int|null, + * maxDuration?: int|null, + * maxHeight?: int|null, + * maxSize?: int|null, + * maxWidth?: int|null, + * viewOnce?: bool|null, + * } + */ +final class Attachment implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Supported MIME types or MIME patterns for this file message type. Missing MIME types should be treated as rejected. + * + * @var array> $mimeTypes + */ + #[Required(map: MimeType::class)] + public array $mimeTypes; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $caption + */ + #[Optional(enum: Caption::class)] + public ?int $caption; + + /** + * Maximum caption length when captions are supported. + */ + #[Optional] + public ?int $maxCaptionLength; + + /** + * Maximum audio or video duration in seconds. + */ + #[Optional] + public ?int $maxDuration; + + /** + * Maximum image or video height in pixels. + */ + #[Optional] + public ?int $maxHeight; + + /** + * Maximum file size in bytes. + */ + #[Optional] + public ?int $maxSize; + + /** + * Maximum image or video width in pixels. + */ + #[Optional] + public ?int $maxWidth; + + /** + * True if this file type can be sent as view-once media. + */ + #[Optional] + public ?bool $viewOnce; + + /** + * `new Attachment()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Attachment::with(mimeTypes: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Attachment)->withMimeTypes(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param array> $mimeTypes + * @param Caption|value-of|null $caption + */ + public static function with( + array $mimeTypes, + Caption|int|null $caption = null, + ?int $maxCaptionLength = null, + ?int $maxDuration = null, + ?int $maxHeight = null, + ?int $maxSize = null, + ?int $maxWidth = null, + ?bool $viewOnce = null, + ): self { + $self = new self; + + $self['mimeTypes'] = $mimeTypes; + + null !== $caption && $self['caption'] = $caption; + null !== $maxCaptionLength && $self['maxCaptionLength'] = $maxCaptionLength; + null !== $maxDuration && $self['maxDuration'] = $maxDuration; + null !== $maxHeight && $self['maxHeight'] = $maxHeight; + null !== $maxSize && $self['maxSize'] = $maxSize; + null !== $maxWidth && $self['maxWidth'] = $maxWidth; + null !== $viewOnce && $self['viewOnce'] = $viewOnce; + + return $self; + } + + /** + * Supported MIME types or MIME patterns for this file message type. Missing MIME types should be treated as rejected. + * + * @param array> $mimeTypes + */ + public function withMimeTypes(array $mimeTypes): self + { + $self = clone $this; + $self['mimeTypes'] = $mimeTypes; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Caption|value-of $caption + */ + public function withCaption(Caption|int $caption): self + { + $self = clone $this; + $self['caption'] = $caption; + + return $self; + } + + /** + * Maximum caption length when captions are supported. + */ + public function withMaxCaptionLength(int $maxCaptionLength): self + { + $self = clone $this; + $self['maxCaptionLength'] = $maxCaptionLength; + + return $self; + } + + /** + * Maximum audio or video duration in seconds. + */ + public function withMaxDuration(int $maxDuration): self + { + $self = clone $this; + $self['maxDuration'] = $maxDuration; + + return $self; + } + + /** + * Maximum image or video height in pixels. + */ + public function withMaxHeight(int $maxHeight): self + { + $self = clone $this; + $self['maxHeight'] = $maxHeight; + + return $self; + } + + /** + * Maximum file size in bytes. + */ + public function withMaxSize(int $maxSize): self + { + $self = clone $this; + $self['maxSize'] = $maxSize; + + return $self; + } + + /** + * Maximum image or video width in pixels. + */ + public function withMaxWidth(int $maxWidth): self + { + $self = clone $this; + $self['maxWidth'] = $maxWidth; + + return $self; + } + + /** + * True if this file type can be sent as view-once media. + */ + public function withViewOnce(bool $viewOnce): self + { + $self = clone $this; + $self['viewOnce'] = $viewOnce; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/Attachment/Caption.php b/src/Chats/Chat/Capabilities/Attachment/Caption.php new file mode 100644 index 0000000..742fbf7 --- /dev/null +++ b/src/Chats/Chat/Capabilities/Attachment/Caption.php @@ -0,0 +1,21 @@ +|null, + * types?: list>|null, + * } + */ +final class DisappearingTimer implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * True if empty timer objects should be omitted from message content. + */ + #[Optional] + public ?bool $omitEmptyTimer; + + /** + * Allowed disappearing timer values in milliseconds. Omitted means any timer is allowed. + * + * @var list|null $timers + */ + #[Optional(list: 'int')] + public ?array $timers; + + /** + * Supported disappearing timer types. + * + * @var list>|null $types + */ + #[Optional(list: Type::class)] + public ?array $types; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list|null $timers + * @param list>|null $types + */ + public static function with( + ?bool $omitEmptyTimer = null, + ?array $timers = null, + ?array $types = null + ): self { + $self = new self; + + null !== $omitEmptyTimer && $self['omitEmptyTimer'] = $omitEmptyTimer; + null !== $timers && $self['timers'] = $timers; + null !== $types && $self['types'] = $types; + + return $self; + } + + /** + * True if empty timer objects should be omitted from message content. + */ + public function withOmitEmptyTimer(bool $omitEmptyTimer): self + { + $self = clone $this; + $self['omitEmptyTimer'] = $omitEmptyTimer; + + return $self; + } + + /** + * Allowed disappearing timer values in milliseconds. Omitted means any timer is allowed. + * + * @param list $timers + */ + public function withTimers(array $timers): self + { + $self = clone $this; + $self['timers'] = $timers; + + return $self; + } + + /** + * Supported disappearing timer types. + * + * @param list> $types + */ + public function withTypes(array $types): self + { + $self = clone $this; + $self['types'] = $types; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/DisappearingTimer/Type.php b/src/Chats/Chat/Capabilities/DisappearingTimer/Type.php new file mode 100644 index 0000000..e606ae0 --- /dev/null +++ b/src/Chats/Chat/Capabilities/DisappearingTimer/Type.php @@ -0,0 +1,12 @@ +, + * acceptWithMessage?: null|AcceptWithMessage|value-of, + * } + */ +final class MessageRequest implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $acceptWithButton + */ + #[Optional(enum: AcceptWithButton::class)] + public ?int $acceptWithButton; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $acceptWithMessage + */ + #[Optional(enum: AcceptWithMessage::class)] + public ?int $acceptWithMessage; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AcceptWithButton|value-of|null $acceptWithButton + * @param AcceptWithMessage|value-of|null $acceptWithMessage + */ + public static function with( + AcceptWithButton|int|null $acceptWithButton = null, + AcceptWithMessage|int|null $acceptWithMessage = null, + ): self { + $self = new self; + + null !== $acceptWithButton && $self['acceptWithButton'] = $acceptWithButton; + null !== $acceptWithMessage && $self['acceptWithMessage'] = $acceptWithMessage; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param AcceptWithButton|value-of $acceptWithButton + */ + public function withAcceptWithButton( + AcceptWithButton|int $acceptWithButton + ): self { + $self = clone $this; + $self['acceptWithButton'] = $acceptWithButton; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param AcceptWithMessage|value-of $acceptWithMessage + */ + public function withAcceptWithMessage( + AcceptWithMessage|int $acceptWithMessage + ): self { + $self = clone $this; + $self['acceptWithMessage'] = $acceptWithMessage; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/MessageRequest/AcceptWithButton.php b/src/Chats/Chat/Capabilities/MessageRequest/AcceptWithButton.php new file mode 100644 index 0000000..f612299 --- /dev/null +++ b/src/Chats/Chat/Capabilities/MessageRequest/AcceptWithButton.php @@ -0,0 +1,21 @@ +, + * invite?: null|Invite|value-of, + * kick?: null|Kick|value-of, + * leave?: null|Leave|value-of, + * revokeInvite?: null|RevokeInvite|value-of, + * } + */ +final class ParticipantActions implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $ban + */ + #[Optional(enum: Ban::class)] + public ?int $ban; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $invite + */ + #[Optional(enum: Invite::class)] + public ?int $invite; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $kick + */ + #[Optional(enum: Kick::class)] + public ?int $kick; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $leave + */ + #[Optional(enum: Leave::class)] + public ?int $leave; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of|null $revokeInvite + */ + #[Optional(enum: RevokeInvite::class)] + public ?int $revokeInvite; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Ban|value-of|null $ban + * @param Invite|value-of|null $invite + * @param Kick|value-of|null $kick + * @param Leave|value-of|null $leave + * @param RevokeInvite|value-of|null $revokeInvite + */ + public static function with( + Ban|int|null $ban = null, + Invite|int|null $invite = null, + Kick|int|null $kick = null, + Leave|int|null $leave = null, + RevokeInvite|int|null $revokeInvite = null, + ): self { + $self = new self; + + null !== $ban && $self['ban'] = $ban; + null !== $invite && $self['invite'] = $invite; + null !== $kick && $self['kick'] = $kick; + null !== $leave && $self['leave'] = $leave; + null !== $revokeInvite && $self['revokeInvite'] = $revokeInvite; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Ban|value-of $ban + */ + public function withBan(Ban|int $ban): self + { + $self = clone $this; + $self['ban'] = $ban; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Invite|value-of $invite + */ + public function withInvite(Invite|int $invite): self + { + $self = clone $this; + $self['invite'] = $invite; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Kick|value-of $kick + */ + public function withKick(Kick|int $kick): self + { + $self = clone $this; + $self['kick'] = $kick; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Leave|value-of $leave + */ + public function withLeave(Leave|int $leave): self + { + $self = clone $this; + $self['leave'] = $leave; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param RevokeInvite|value-of $revokeInvite + */ + public function withRevokeInvite(RevokeInvite|int $revokeInvite): self + { + $self = clone $this; + $self['revokeInvite'] = $revokeInvite; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/ParticipantActions/Ban.php b/src/Chats/Chat/Capabilities/ParticipantActions/Ban.php new file mode 100644 index 0000000..96d3af9 --- /dev/null +++ b/src/Chats/Chat/Capabilities/ParticipantActions/Ban.php @@ -0,0 +1,21 @@ + */ + use SdkModel; + + /** + * Chat avatar state capability. + */ + #[Optional] + public ?Avatar $avatar; + + /** + * Chat description/topic state capability. + */ + #[Optional] + public ?Description $description; + + /** + * Disappearing-message timer state capability. + */ + #[Optional] + public ?DisappearingTimer $disappearingTimer; + + /** + * Chat title state capability. + */ + #[Optional] + public ?Title $title; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Avatar|AvatarShape|null $avatar + * @param Description|DescriptionShape|null $description + * @param DisappearingTimer|DisappearingTimerShape|null $disappearingTimer + * @param Title|TitleShape|null $title + */ + public static function with( + Avatar|array|null $avatar = null, + Description|array|null $description = null, + DisappearingTimer|array|null $disappearingTimer = null, + Title|array|null $title = null, + ): self { + $self = new self; + + null !== $avatar && $self['avatar'] = $avatar; + null !== $description && $self['description'] = $description; + null !== $disappearingTimer && $self['disappearingTimer'] = $disappearingTimer; + null !== $title && $self['title'] = $title; + + return $self; + } + + /** + * Chat avatar state capability. + * + * @param Avatar|AvatarShape $avatar + */ + public function withAvatar(Avatar|array $avatar): self + { + $self = clone $this; + $self['avatar'] = $avatar; + + return $self; + } + + /** + * Chat description/topic state capability. + * + * @param Description|DescriptionShape $description + */ + public function withDescription(Description|array $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * Disappearing-message timer state capability. + * + * @param DisappearingTimer|DisappearingTimerShape $disappearingTimer + */ + public function withDisappearingTimer( + DisappearingTimer|array $disappearingTimer, + ): self { + $self = clone $this; + $self['disappearingTimer'] = $disappearingTimer; + + return $self; + } + + /** + * Chat title state capability. + * + * @param Title|TitleShape $title + */ + public function withTitle(Title|array $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/State/Avatar.php b/src/Chats/Chat/Capabilities/State/Avatar.php new file mode 100644 index 0000000..7c5571b --- /dev/null +++ b/src/Chats/Chat/Capabilities/State/Avatar.php @@ -0,0 +1,77 @@ +} + */ +final class Avatar implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of $level + */ + #[Required(enum: Level::class)] + public int $level; + + /** + * `new Avatar()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Avatar::with(level: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Avatar)->withLevel(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Level|value-of $level + */ + public static function with(Level|int $level): self + { + $self = new self; + + $self['level'] = $level; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Level|value-of $level + */ + public function withLevel(Level|int $level): self + { + $self = clone $this; + $self['level'] = $level; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/State/Avatar/Level.php b/src/Chats/Chat/Capabilities/State/Avatar/Level.php new file mode 100644 index 0000000..5af7747 --- /dev/null +++ b/src/Chats/Chat/Capabilities/State/Avatar/Level.php @@ -0,0 +1,21 @@ +} + */ +final class Description implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of $level + */ + #[Required(enum: Level::class)] + public int $level; + + /** + * `new Description()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Description::with(level: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Description)->withLevel(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Level|value-of $level + */ + public static function with(Level|int $level): self + { + $self = new self; + + $self['level'] = $level; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Level|value-of $level + */ + public function withLevel(Level|int $level): self + { + $self = clone $this; + $self['level'] = $level; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/State/Description/Level.php b/src/Chats/Chat/Capabilities/State/Description/Level.php new file mode 100644 index 0000000..b494808 --- /dev/null +++ b/src/Chats/Chat/Capabilities/State/Description/Level.php @@ -0,0 +1,21 @@ +} + */ +final class DisappearingTimer implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of $level + */ + #[Required(enum: Level::class)] + public int $level; + + /** + * `new DisappearingTimer()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * DisappearingTimer::with(level: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new DisappearingTimer)->withLevel(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Level|value-of $level + */ + public static function with(Level|int $level): self + { + $self = new self; + + $self['level'] = $level; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Level|value-of $level + */ + public function withLevel(Level|int $level): self + { + $self = clone $this; + $self['level'] = $level; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/State/DisappearingTimer/Level.php b/src/Chats/Chat/Capabilities/State/DisappearingTimer/Level.php new file mode 100644 index 0000000..96baa8a --- /dev/null +++ b/src/Chats/Chat/Capabilities/State/DisappearingTimer/Level.php @@ -0,0 +1,21 @@ +} + */ +final class Title implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @var value-of $level + */ + #[Required(enum: Level::class)] + public int $level; + + /** + * `new Title()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Title::with(level: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Title)->withLevel(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Level|value-of $level + */ + public static function with(Level|int $level): self + { + $self = new self; + + $self['level'] = $level; + + return $self; + } + + /** + * -2: rejected, -1: dropped, 0: unsupported, 1: partially supported, 2: fully supported. + * + * @param Level|value-of $level + */ + public function withLevel(Level|int $level): self + { + $self = clone $this; + $self['level'] = $level; + + return $self; + } +} diff --git a/src/Chats/Chat/Capabilities/State/Title/Level.php b/src/Chats/Chat/Capabilities/State/Title/Level.php new file mode 100644 index 0000000..1e1059e --- /dev/null +++ b/src/Chats/Chat/Capabilities/State/Title/Level.php @@ -0,0 +1,21 @@ +|null + * } + */ +final class Draft implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Matrix HTML draft body. + */ + #[Required] + public string $text; + + /** + * Draft attachments keyed by attachment ID. + * + * @var array|null $attachments + */ + #[Optional(map: Attachment::class)] + public ?array $attachments; + + /** + * `new Draft()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Draft::with(text: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Draft)->withText(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param array|null $attachments + */ + public static function with(string $text, ?array $attachments = null): self + { + $self = new self; + + $self['text'] = $text; + + null !== $attachments && $self['attachments'] = $attachments; + + return $self; + } + + /** + * Matrix HTML draft body. + */ + public function withText(string $text): self + { + $self = clone $this; + $self['text'] = $text; + + return $self; + } + + /** + * Draft attachments keyed by attachment ID. + * + * @param array $attachments + */ + public function withAttachments(array $attachments): self + { + $self = clone $this; + $self['attachments'] = $attachments; + + return $self; + } +} diff --git a/src/Chats/Chat/Draft/Attachment.php b/src/Chats/Chat/Draft/Attachment.php new file mode 100644 index 0000000..e525fec --- /dev/null +++ b/src/Chats/Chat/Draft/Attachment.php @@ -0,0 +1,246 @@ +, + * audioDurationSeconds?: float|null, + * fileName?: string|null, + * filePath?: string|null, + * fileSize?: float|null, + * mimeType?: string|null, + * size?: null|Size|SizeShape, + * stickerID?: string|null, + * } + */ +final class Attachment implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Draft attachment identifier. + */ + #[Required] + public string $id; + + /** + * Draft attachment type. GIF and recorded audio are mutually exclusive types. + * + * @var value-of $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * Audio duration in seconds if known. + */ + #[Optional] + public ?float $audioDurationSeconds; + + /** + * Original filename if available. + */ + #[Optional] + public ?string $fileName; + + /** + * Local filesystem path for the draft attachment. + */ + #[Optional] + public ?string $filePath; + + /** + * File size in bytes if known. + */ + #[Optional] + public ?float $fileSize; + + /** + * MIME type if known. + */ + #[Optional] + public ?string $mimeType; + + /** + * Pixel dimensions of the attachment. + */ + #[Optional] + public ?Size $size; + + /** + * Sticker identifier if the draft attachment is a sticker. + */ + #[Optional] + public ?string $stickerID; + + /** + * `new Attachment()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Attachment::with(id: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Attachment)->withID(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of $type + * @param Size|SizeShape|null $size + */ + public static function with( + string $id, + Type|string $type, + ?float $audioDurationSeconds = null, + ?string $fileName = null, + ?string $filePath = null, + ?float $fileSize = null, + ?string $mimeType = null, + Size|array|null $size = null, + ?string $stickerID = null, + ): self { + $self = new self; + + $self['id'] = $id; + $self['type'] = $type; + + null !== $audioDurationSeconds && $self['audioDurationSeconds'] = $audioDurationSeconds; + null !== $fileName && $self['fileName'] = $fileName; + null !== $filePath && $self['filePath'] = $filePath; + null !== $fileSize && $self['fileSize'] = $fileSize; + null !== $mimeType && $self['mimeType'] = $mimeType; + null !== $size && $self['size'] = $size; + null !== $stickerID && $self['stickerID'] = $stickerID; + + return $self; + } + + /** + * Draft attachment identifier. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * Draft attachment type. GIF and recorded audio are mutually exclusive types. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Audio duration in seconds if known. + */ + public function withAudioDurationSeconds(float $audioDurationSeconds): self + { + $self = clone $this; + $self['audioDurationSeconds'] = $audioDurationSeconds; + + return $self; + } + + /** + * Original filename if available. + */ + public function withFileName(string $fileName): self + { + $self = clone $this; + $self['fileName'] = $fileName; + + return $self; + } + + /** + * Local filesystem path for the draft attachment. + */ + public function withFilePath(string $filePath): self + { + $self = clone $this; + $self['filePath'] = $filePath; + + return $self; + } + + /** + * File size in bytes if known. + */ + public function withFileSize(float $fileSize): self + { + $self = clone $this; + $self['fileSize'] = $fileSize; + + return $self; + } + + /** + * MIME type if known. + */ + public function withMimeType(string $mimeType): self + { + $self = clone $this; + $self['mimeType'] = $mimeType; + + return $self; + } + + /** + * Pixel dimensions of the attachment. + * + * @param Size|SizeShape $size + */ + public function withSize(Size|array $size): self + { + $self = clone $this; + $self['size'] = $size; + + return $self; + } + + /** + * Sticker identifier if the draft attachment is a sticker. + */ + public function withStickerID(string $stickerID): self + { + $self = clone $this; + $self['stickerID'] = $stickerID; + + return $self; + } +} diff --git a/src/Chats/Chat/Draft/Attachment/Size.php b/src/Chats/Chat/Draft/Attachment/Size.php new file mode 100644 index 0000000..a31a06a --- /dev/null +++ b/src/Chats/Chat/Draft/Attachment/Size.php @@ -0,0 +1,62 @@ + */ + use SdkModel; + + #[Optional] + public ?float $height; + + #[Optional] + public ?float $width; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?float $height = null, ?float $width = null): self + { + $self = new self; + + null !== $height && $self['height'] = $height; + null !== $width && $self['width'] = $width; + + return $self; + } + + public function withHeight(float $height): self + { + $self = clone $this; + $self['height'] = $height; + + return $self; + } + + public function withWidth(float $width): self + { + $self = clone $this; + $self['width'] = $width; + + return $self; + } +} diff --git a/src/Chats/Chat/Draft/Attachment/Type.php b/src/Chats/Chat/Draft/Attachment/Type.php new file mode 100644 index 0000000..e387fd8 --- /dev/null +++ b/src/Chats/Chat/Draft/Attachment/Type.php @@ -0,0 +1,17 @@ +, total: int + * hasMore: bool, items: list, total: int * } */ final class Participants implements BaseModel @@ -32,9 +32,9 @@ final class Participants implements BaseModel /** * Participants returned for this chat (limited by the request; may be a subset). * - * @var list $items + * @var list $items */ - #[Required(list: User::class)] + #[Required(list: Item::class)] public array $items; /** @@ -67,7 +67,7 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * - * @param list $items + * @param list $items */ public static function with(bool $hasMore, array $items, int $total): self { @@ -94,7 +94,7 @@ public function withHasMore(bool $hasMore): self /** * Participants returned for this chat (limited by the request; may be a subset). * - * @param list $items + * @param list $items */ public function withItems(array $items): self { diff --git a/src/Chats/Chat/Participants/Item.php b/src/Chats/Chat/Participants/Item.php new file mode 100644 index 0000000..5943db9 --- /dev/null +++ b/src/Chats/Chat/Participants/Item.php @@ -0,0 +1,275 @@ + */ + use SdkModel; + + /** + * Stable Beeper user ID. Use as the primary key when referencing a person. + */ + #[Required] + public string $id; + + /** + * True if Beeper cannot initiate messages to this user (e.g., blocked, network restriction, or no DM path). The user may still message you. + */ + #[Optional] + public ?bool $cannotMessage; + + /** + * Email address if known. Not guaranteed verified. + */ + #[Optional] + public ?string $email; + + /** + * Display name as shown in clients (e.g., 'Alice Example'). May include emojis. + */ + #[Optional] + public ?string $fullName; + + /** + * Avatar image URL if available. This may be a remote URL, Matrix media URL, data URL, or local filesystem URL depending on source and endpoint. May be temporary or local-only to this device; download promptly if durable access is needed. + */ + #[Optional] + public ?string $imgURL; + + /** + * True if this user represents the authenticated account's own identity. + */ + #[Optional] + public ?bool $isSelf; + + /** + * User's phone number in E.164 format (e.g., '+14155552671'). Omit if unknown. + */ + #[Optional] + public ?string $phoneNumber; + + /** + * Human-readable handle if available (e.g., '@alice'). May be network-specific and not globally unique. + */ + #[Optional] + public ?string $username; + + /** + * True if this participant has admin privileges in the chat. + */ + #[Optional] + public ?bool $isAdmin; + + /** + * True if this participant represents a network or bridge bot. + */ + #[Optional] + public ?bool $isNetworkBot; + + /** + * True if this participant has been invited but has not joined yet. + */ + #[Optional] + public ?bool $isPending; + + /** + * `new Item()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Item::with(id: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Item)->withID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $id, + ?bool $cannotMessage = null, + ?string $email = null, + ?string $fullName = null, + ?string $imgURL = null, + ?bool $isSelf = null, + ?string $phoneNumber = null, + ?string $username = null, + ?bool $isAdmin = null, + ?bool $isNetworkBot = null, + ?bool $isPending = null, + ): self { + $self = new self; + + $self['id'] = $id; + + null !== $cannotMessage && $self['cannotMessage'] = $cannotMessage; + null !== $email && $self['email'] = $email; + null !== $fullName && $self['fullName'] = $fullName; + null !== $imgURL && $self['imgURL'] = $imgURL; + null !== $isSelf && $self['isSelf'] = $isSelf; + null !== $phoneNumber && $self['phoneNumber'] = $phoneNumber; + null !== $username && $self['username'] = $username; + null !== $isAdmin && $self['isAdmin'] = $isAdmin; + null !== $isNetworkBot && $self['isNetworkBot'] = $isNetworkBot; + null !== $isPending && $self['isPending'] = $isPending; + + return $self; + } + + /** + * Stable Beeper user ID. Use as the primary key when referencing a person. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * True if Beeper cannot initiate messages to this user (e.g., blocked, network restriction, or no DM path). The user may still message you. + */ + public function withCannotMessage(bool $cannotMessage): self + { + $self = clone $this; + $self['cannotMessage'] = $cannotMessage; + + return $self; + } + + /** + * Email address if known. Not guaranteed verified. + */ + public function withEmail(string $email): self + { + $self = clone $this; + $self['email'] = $email; + + return $self; + } + + /** + * Display name as shown in clients (e.g., 'Alice Example'). May include emojis. + */ + public function withFullName(string $fullName): self + { + $self = clone $this; + $self['fullName'] = $fullName; + + return $self; + } + + /** + * Avatar image URL if available. This may be a remote URL, Matrix media URL, data URL, or local filesystem URL depending on source and endpoint. May be temporary or local-only to this device; download promptly if durable access is needed. + */ + public function withImgURL(string $imgURL): self + { + $self = clone $this; + $self['imgURL'] = $imgURL; + + return $self; + } + + /** + * True if this user represents the authenticated account's own identity. + */ + public function withIsSelf(bool $isSelf): self + { + $self = clone $this; + $self['isSelf'] = $isSelf; + + return $self; + } + + /** + * User's phone number in E.164 format (e.g., '+14155552671'). Omit if unknown. + */ + public function withPhoneNumber(string $phoneNumber): self + { + $self = clone $this; + $self['phoneNumber'] = $phoneNumber; + + return $self; + } + + /** + * Human-readable handle if available (e.g., '@alice'). May be network-specific and not globally unique. + */ + public function withUsername(string $username): self + { + $self = clone $this; + $self['username'] = $username; + + return $self; + } + + /** + * True if this participant has admin privileges in the chat. + */ + public function withIsAdmin(bool $isAdmin): self + { + $self = clone $this; + $self['isAdmin'] = $isAdmin; + + return $self; + } + + /** + * True if this participant represents a network or bridge bot. + */ + public function withIsNetworkBot(bool $isNetworkBot): self + { + $self = clone $this; + $self['isNetworkBot'] = $isNetworkBot; + + return $self; + } + + /** + * True if this participant has been invited but has not joined yet. + */ + public function withIsPending(bool $isPending): self + { + $self = clone $this; + $self['isPending'] = $isPending; + + return $self; + } +} diff --git a/src/Chats/Chat/Reminder.php b/src/Chats/Chat/Reminder.php new file mode 100644 index 0000000..0808ea7 --- /dev/null +++ b/src/Chats/Chat/Reminder.php @@ -0,0 +1,79 @@ + */ + use SdkModel; + + /** + * Cancel reminder if someone messages in the chat. + */ + #[Optional] + public ?bool $dismissOnIncomingMessage; + + /** + * Timestamp when the reminder should trigger. + */ + #[Optional] + public ?\DateTimeInterface $remindAt; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?bool $dismissOnIncomingMessage = null, + ?\DateTimeInterface $remindAt = null + ): self { + $self = new self; + + null !== $dismissOnIncomingMessage && $self['dismissOnIncomingMessage'] = $dismissOnIncomingMessage; + null !== $remindAt && $self['remindAt'] = $remindAt; + + return $self; + } + + /** + * Cancel reminder if someone messages in the chat. + */ + public function withDismissOnIncomingMessage( + bool $dismissOnIncomingMessage + ): self { + $self = clone $this; + $self['dismissOnIncomingMessage'] = $dismissOnIncomingMessage; + + return $self; + } + + /** + * Timestamp when the reminder should trigger. + */ + public function withRemindAt(\DateTimeInterface $remindAt): self + { + $self = clone $this; + $self['remindAt'] = $remindAt; + + return $self; + } +} diff --git a/src/Chats/Chat/Snooze.php b/src/Chats/Chat/Snooze.php new file mode 100644 index 0000000..a002230 --- /dev/null +++ b/src/Chats/Chat/Snooze.php @@ -0,0 +1,78 @@ + */ + use SdkModel; + + /** + * Timestamp when the snooze expires. + */ + #[Optional] + public ?\DateTimeInterface $snoozeUntil; + + /** + * Timestamp when the user set the snooze. + */ + #[Optional] + public ?\DateTimeInterface $userSnoozedAt; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?\DateTimeInterface $snoozeUntil = null, + ?\DateTimeInterface $userSnoozedAt = null, + ): self { + $self = new self; + + null !== $snoozeUntil && $self['snoozeUntil'] = $snoozeUntil; + null !== $userSnoozedAt && $self['userSnoozedAt'] = $userSnoozedAt; + + return $self; + } + + /** + * Timestamp when the snooze expires. + */ + public function withSnoozeUntil(\DateTimeInterface $snoozeUntil): self + { + $self = clone $this; + $self['snoozeUntil'] = $snoozeUntil; + + return $self; + } + + /** + * Timestamp when the user set the snooze. + */ + public function withUserSnoozedAt(\DateTimeInterface $userSnoozedAt): self + { + $self = clone $this; + $self['userSnoozedAt'] = $userSnoozedAt; + + return $self; + } +} diff --git a/src/Chats/ChatCreateParams.php b/src/Chats/ChatCreateParams.php index b2088bf..550038f 100644 --- a/src/Chats/ChatCreateParams.php +++ b/src/Chats/ChatCreateParams.php @@ -12,7 +12,7 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** - * Create a direct or group chat from participant IDs. + * Create a direct or group chat from participant IDs. Returns the created chat. * * @see BeeperDesktop\Services\ChatsService::create() * diff --git a/src/Chats/ChatListResponse.php b/src/Chats/ChatListResponse.php index 9fec51d..dd44631 100644 --- a/src/Chats/ChatListResponse.php +++ b/src/Chats/ChatListResponse.php @@ -4,7 +4,11 @@ namespace BeeperDesktop\Chats; +use BeeperDesktop\Chats\Chat\Capabilities; +use BeeperDesktop\Chats\Chat\Draft; use BeeperDesktop\Chats\Chat\Participants; +use BeeperDesktop\Chats\Chat\Reminder; +use BeeperDesktop\Chats\Chat\Snooze; use BeeperDesktop\Chats\Chat\Type; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Attributes\Required; @@ -13,22 +17,40 @@ use BeeperDesktop\Message; /** + * Chat with optional last message preview. + * * @phpstan-import-type ParticipantsShape from \BeeperDesktop\Chats\Chat\Participants + * @phpstan-import-type CapabilitiesShape from \BeeperDesktop\Chats\Chat\Capabilities + * @phpstan-import-type DraftShape from \BeeperDesktop\Chats\Chat\Draft + * @phpstan-import-type ReminderShape from \BeeperDesktop\Chats\Chat\Reminder + * @phpstan-import-type SnoozeShape from \BeeperDesktop\Chats\Chat\Snooze * @phpstan-import-type MessageShape from \BeeperDesktop\Message * * @phpstan-type ChatListResponseShape = array{ * id: string, * accountID: string, + * network: string, * participants: Participants|ParticipantsShape, * title: string, * type: Type|value-of, * unreadCount: int, + * capabilities?: null|Capabilities|CapabilitiesShape, + * description?: string|null, + * draft?: null|Draft|DraftShape, + * imgURL?: string|null, * isArchived?: bool|null, + * isLowPriority?: bool|null, + * isMarkedUnread?: bool|null, * isMuted?: bool|null, * isPinned?: bool|null, + * isReadOnly?: bool|null, * lastActivity?: \DateTimeInterface|null, * lastReadMessageSortKey?: string|null, * localChatID?: string|null, + * messageExpirySeconds?: int|null, + * reminder?: null|Reminder|ReminderShape, + * snooze?: null|Snooze|SnoozeShape, + * unreadMentionsCount?: int|null, * preview?: null|Message|MessageShape, * } */ @@ -49,6 +71,12 @@ final class ChatListResponse implements BaseModel #[Required] public string $accountID; + /** + * Display-only human-readable account/network name. + */ + #[Required] + public string $network; + /** * Chat participants information. */ @@ -75,12 +103,48 @@ final class ChatListResponse implements BaseModel #[Required] public int $unreadCount; + /** + * Chat capabilities reported by the platform. + */ + #[Optional] + public ?Capabilities $capabilities; + + /** + * Group chat description/topic when available. + */ + #[Optional(nullable: true)] + public ?string $description; + + /** + * Current draft object for this chat, or null when no draft is set. + */ + #[Optional(nullable: true)] + public ?Draft $draft; + + /** + * Local filesystem path to the chat avatar image when available. + */ + #[Optional(nullable: true)] + public ?string $imgURL; + /** * True if chat is archived. */ #[Optional] public ?bool $isArchived; + /** + * True if chat is marked low priority. + */ + #[Optional] + public ?bool $isLowPriority; + + /** + * True if the chat was explicitly marked unread by the authenticated user. + */ + #[Optional] + public ?bool $isMarkedUnread; + /** * True if chat notifications are muted. */ @@ -93,6 +157,12 @@ final class ChatListResponse implements BaseModel #[Optional] public ?bool $isPinned; + /** + * True if messages cannot be sent in this chat. + */ + #[Optional] + public ?bool $isReadOnly; + /** * Timestamp of last activity. */ @@ -111,6 +181,30 @@ final class ChatListResponse implements BaseModel #[Optional(nullable: true)] public ?string $localChatID; + /** + * Disappearing-message timer in seconds when available. + */ + #[Optional(nullable: true)] + public ?int $messageExpirySeconds; + + /** + * Current reminder for this chat, or null when no reminder is set. + */ + #[Optional(nullable: true)] + public ?Reminder $reminder; + + /** + * Current snooze state for this chat, or null when no snooze is set. + */ + #[Optional(nullable: true)] + public ?Snooze $snooze; + + /** + * Number of unread messages that mention the authenticated user or @room. + */ + #[Optional] + public ?int $unreadMentionsCount; + #[Optional] public ?Message $preview; @@ -122,6 +216,7 @@ final class ChatListResponse implements BaseModel * ChatListResponse::with( * id: ..., * accountID: ..., + * network: ..., * participants: ..., * title: ..., * type: ..., @@ -135,6 +230,7 @@ final class ChatListResponse implements BaseModel * (new ChatListResponse) * ->withID(...) * ->withAccountID(...) + * ->withNetwork(...) * ->withParticipants(...) * ->withTitle(...) * ->withType(...) @@ -153,38 +249,66 @@ public function __construct() * * @param Participants|ParticipantsShape $participants * @param Type|value-of $type + * @param Capabilities|CapabilitiesShape|null $capabilities + * @param Draft|DraftShape|null $draft + * @param Reminder|ReminderShape|null $reminder + * @param Snooze|SnoozeShape|null $snooze * @param Message|MessageShape|null $preview */ public static function with( string $id, string $accountID, + string $network, Participants|array $participants, string $title, Type|string $type, int $unreadCount, + Capabilities|array|null $capabilities = null, + ?string $description = null, + Draft|array|null $draft = null, + ?string $imgURL = null, ?bool $isArchived = null, + ?bool $isLowPriority = null, + ?bool $isMarkedUnread = null, ?bool $isMuted = null, ?bool $isPinned = null, + ?bool $isReadOnly = null, ?\DateTimeInterface $lastActivity = null, ?string $lastReadMessageSortKey = null, ?string $localChatID = null, + ?int $messageExpirySeconds = null, + Reminder|array|null $reminder = null, + Snooze|array|null $snooze = null, + ?int $unreadMentionsCount = null, Message|array|null $preview = null, ): self { $self = new self; $self['id'] = $id; $self['accountID'] = $accountID; + $self['network'] = $network; $self['participants'] = $participants; $self['title'] = $title; $self['type'] = $type; $self['unreadCount'] = $unreadCount; + null !== $capabilities && $self['capabilities'] = $capabilities; + null !== $description && $self['description'] = $description; + null !== $draft && $self['draft'] = $draft; + null !== $imgURL && $self['imgURL'] = $imgURL; null !== $isArchived && $self['isArchived'] = $isArchived; + null !== $isLowPriority && $self['isLowPriority'] = $isLowPriority; + null !== $isMarkedUnread && $self['isMarkedUnread'] = $isMarkedUnread; null !== $isMuted && $self['isMuted'] = $isMuted; null !== $isPinned && $self['isPinned'] = $isPinned; + null !== $isReadOnly && $self['isReadOnly'] = $isReadOnly; null !== $lastActivity && $self['lastActivity'] = $lastActivity; null !== $lastReadMessageSortKey && $self['lastReadMessageSortKey'] = $lastReadMessageSortKey; null !== $localChatID && $self['localChatID'] = $localChatID; + null !== $messageExpirySeconds && $self['messageExpirySeconds'] = $messageExpirySeconds; + null !== $reminder && $self['reminder'] = $reminder; + null !== $snooze && $self['snooze'] = $snooze; + null !== $unreadMentionsCount && $self['unreadMentionsCount'] = $unreadMentionsCount; null !== $preview && $self['preview'] = $preview; return $self; @@ -212,6 +336,17 @@ public function withAccountID(string $accountID): self return $self; } + /** + * Display-only human-readable account/network name. + */ + public function withNetwork(string $network): self + { + $self = clone $this; + $self['network'] = $network; + + return $self; + } + /** * Chat participants information. * @@ -260,6 +395,54 @@ public function withUnreadCount(int $unreadCount): self return $self; } + /** + * Chat capabilities reported by the platform. + * + * @param Capabilities|CapabilitiesShape $capabilities + */ + public function withCapabilities(Capabilities|array $capabilities): self + { + $self = clone $this; + $self['capabilities'] = $capabilities; + + return $self; + } + + /** + * Group chat description/topic when available. + */ + public function withDescription(?string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * Current draft object for this chat, or null when no draft is set. + * + * @param Draft|DraftShape|null $draft + */ + public function withDraft(Draft|array|null $draft): self + { + $self = clone $this; + $self['draft'] = $draft; + + return $self; + } + + /** + * Local filesystem path to the chat avatar image when available. + */ + public function withImgURL(?string $imgURL): self + { + $self = clone $this; + $self['imgURL'] = $imgURL; + + return $self; + } + /** * True if chat is archived. */ @@ -271,6 +454,28 @@ public function withIsArchived(bool $isArchived): self return $self; } + /** + * True if chat is marked low priority. + */ + public function withIsLowPriority(bool $isLowPriority): self + { + $self = clone $this; + $self['isLowPriority'] = $isLowPriority; + + return $self; + } + + /** + * True if the chat was explicitly marked unread by the authenticated user. + */ + public function withIsMarkedUnread(bool $isMarkedUnread): self + { + $self = clone $this; + $self['isMarkedUnread'] = $isMarkedUnread; + + return $self; + } + /** * True if chat notifications are muted. */ @@ -293,6 +498,17 @@ public function withIsPinned(bool $isPinned): self return $self; } + /** + * True if messages cannot be sent in this chat. + */ + public function withIsReadOnly(bool $isReadOnly): self + { + $self = clone $this; + $self['isReadOnly'] = $isReadOnly; + + return $self; + } + /** * Timestamp of last activity. */ @@ -327,6 +543,54 @@ public function withLocalChatID(?string $localChatID): self return $self; } + /** + * Disappearing-message timer in seconds when available. + */ + public function withMessageExpirySeconds(?int $messageExpirySeconds): self + { + $self = clone $this; + $self['messageExpirySeconds'] = $messageExpirySeconds; + + return $self; + } + + /** + * Current reminder for this chat, or null when no reminder is set. + * + * @param Reminder|ReminderShape|null $reminder + */ + public function withReminder(Reminder|array|null $reminder): self + { + $self = clone $this; + $self['reminder'] = $reminder; + + return $self; + } + + /** + * Current snooze state for this chat, or null when no snooze is set. + * + * @param Snooze|SnoozeShape|null $snooze + */ + public function withSnooze(Snooze|array|null $snooze): self + { + $self = clone $this; + $self['snooze'] = $snooze; + + return $self; + } + + /** + * Number of unread messages that mention the authenticated user or @room. + */ + public function withUnreadMentionsCount(int $unreadMentionsCount): self + { + $self = clone $this; + $self['unreadMentionsCount'] = $unreadMentionsCount; + + return $self; + } + /** * @param Message|MessageShape $preview */ diff --git a/src/Chats/ChatMarkReadParams.php b/src/Chats/ChatMarkReadParams.php new file mode 100644 index 0000000..882e5ec --- /dev/null +++ b/src/Chats/ChatMarkReadParams.php @@ -0,0 +1,60 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Optional message ID to mark read through. + */ + #[Optional] + public ?string $messageID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $messageID = null): self + { + $self = new self; + + null !== $messageID && $self['messageID'] = $messageID; + + return $self; + } + + /** + * Optional message ID to mark read through. + */ + public function withMessageID(string $messageID): self + { + $self = clone $this; + $self['messageID'] = $messageID; + + return $self; + } +} diff --git a/src/Chats/ChatMarkUnreadParams.php b/src/Chats/ChatMarkUnreadParams.php new file mode 100644 index 0000000..0167a3d --- /dev/null +++ b/src/Chats/ChatMarkUnreadParams.php @@ -0,0 +1,60 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Optional message ID to mark unread from. + */ + #[Optional] + public ?string $messageID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $messageID = null): self + { + $self = new self; + + null !== $messageID && $self['messageID'] = $messageID; + + return $self; + } + + /** + * Optional message ID to mark unread from. + */ + public function withMessageID(string $messageID): self + { + $self = clone $this; + $self['messageID'] = $messageID; + + return $self; + } +} diff --git a/src/Chats/ChatNewResponse.php b/src/Chats/ChatNewResponse.php index 23d00d4..39b9919 100644 --- a/src/Chats/ChatNewResponse.php +++ b/src/Chats/ChatNewResponse.php @@ -4,6 +4,12 @@ namespace BeeperDesktop\Chats; +use BeeperDesktop\Chats\Chat\Capabilities; +use BeeperDesktop\Chats\Chat\Draft; +use BeeperDesktop\Chats\Chat\Participants; +use BeeperDesktop\Chats\Chat\Reminder; +use BeeperDesktop\Chats\Chat\Snooze; +use BeeperDesktop\Chats\Chat\Type; use BeeperDesktop\Chats\ChatNewResponse\Status; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Attributes\Required; @@ -11,8 +17,39 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** + * @phpstan-import-type ParticipantsShape from \BeeperDesktop\Chats\Chat\Participants + * @phpstan-import-type CapabilitiesShape from \BeeperDesktop\Chats\Chat\Capabilities + * @phpstan-import-type DraftShape from \BeeperDesktop\Chats\Chat\Draft + * @phpstan-import-type ReminderShape from \BeeperDesktop\Chats\Chat\Reminder + * @phpstan-import-type SnoozeShape from \BeeperDesktop\Chats\Chat\Snooze + * * @phpstan-type ChatNewResponseShape = array{ - * chatID: string, status?: null|Status|value-of + * id: string, + * accountID: string, + * network: string, + * participants: Participants|ParticipantsShape, + * title: string, + * type: Type|value-of, + * unreadCount: int, + * capabilities?: null|Capabilities|CapabilitiesShape, + * description?: string|null, + * draft?: null|Draft|DraftShape, + * imgURL?: string|null, + * isArchived?: bool|null, + * isLowPriority?: bool|null, + * isMarkedUnread?: bool|null, + * isMuted?: bool|null, + * isPinned?: bool|null, + * isReadOnly?: bool|null, + * lastActivity?: \DateTimeInterface|null, + * lastReadMessageSortKey?: string|null, + * localChatID?: string|null, + * messageExpirySeconds?: int|null, + * reminder?: null|Reminder|ReminderShape, + * snooze?: null|Snooze|SnoozeShape, + * unreadMentionsCount?: int|null, + * chatID: string, + * status?: null|Status|value-of, * } */ final class ChatNewResponse implements BaseModel @@ -21,13 +58,163 @@ final class ChatNewResponse implements BaseModel use SdkModel; /** - * Newly created chat ID. + * Unique identifier of the chat across Beeper. + */ + #[Required] + public string $id; + + /** + * Account ID this chat belongs to. + */ + #[Required] + public string $accountID; + + /** + * Display-only human-readable account/network name. + */ + #[Required] + public string $network; + + /** + * Chat participants information. + */ + #[Required] + public Participants $participants; + + /** + * Display title of the chat as computed by the client/server. + */ + #[Required] + public string $title; + + /** + * Chat type: 'single' for direct messages, 'group' for group chats. + * + * @var value-of $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * Number of unread messages. + */ + #[Required] + public int $unreadCount; + + /** + * Chat capabilities reported by the platform. + */ + #[Optional] + public ?Capabilities $capabilities; + + /** + * Group chat description/topic when available. + */ + #[Optional(nullable: true)] + public ?string $description; + + /** + * Current draft object for this chat, or null when no draft is set. + */ + #[Optional(nullable: true)] + public ?Draft $draft; + + /** + * Local filesystem path to the chat avatar image when available. + */ + #[Optional(nullable: true)] + public ?string $imgURL; + + /** + * True if chat is archived. + */ + #[Optional] + public ?bool $isArchived; + + /** + * True if chat is marked low priority. + */ + #[Optional] + public ?bool $isLowPriority; + + /** + * True if the chat was explicitly marked unread by the authenticated user. + */ + #[Optional] + public ?bool $isMarkedUnread; + + /** + * True if chat notifications are muted. + */ + #[Optional] + public ?bool $isMuted; + + /** + * True if chat is pinned. + */ + #[Optional] + public ?bool $isPinned; + + /** + * True if messages cannot be sent in this chat. + */ + #[Optional] + public ?bool $isReadOnly; + + /** + * Timestamp of last activity. + */ + #[Optional] + public ?\DateTimeInterface $lastActivity; + + /** + * Last read message sortKey. + */ + #[Optional] + public ?string $lastReadMessageSortKey; + + /** + * Local chat ID specific to this Beeper Desktop installation. + */ + #[Optional(nullable: true)] + public ?string $localChatID; + + /** + * Disappearing-message timer in seconds when available. + */ + #[Optional(nullable: true)] + public ?int $messageExpirySeconds; + + /** + * Current reminder for this chat, or null when no reminder is set. + */ + #[Optional(nullable: true)] + public ?Reminder $reminder; + + /** + * Current snooze state for this chat, or null when no snooze is set. + */ + #[Optional(nullable: true)] + public ?Snooze $snooze; + + /** + * Number of unread messages that mention the authenticated user or @room. + */ + #[Optional] + public ?int $unreadMentionsCount; + + /** + * @deprecated + * + * DEPRECATED - use id instead. Compatibility alias for older clients. */ #[Required] public string $chatID; /** - * Only returned in start mode. 'existing' means an existing chat was reused; 'created' means a new chat was created. + * @deprecated + * + * DEPRECATED - legacy start-chat status for older clients. New clients should inspect the returned Chat instead. * * @var value-of|null $status */ @@ -39,13 +226,30 @@ final class ChatNewResponse implements BaseModel * * To enforce required parameters use * ``` - * ChatNewResponse::with(chatID: ...) + * ChatNewResponse::with( + * id: ..., + * accountID: ..., + * network: ..., + * participants: ..., + * title: ..., + * type: ..., + * unreadCount: ..., + * chatID: ..., + * ) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new ChatNewResponse)->withChatID(...) + * (new ChatNewResponse) + * ->withID(...) + * ->withAccountID(...) + * ->withNetwork(...) + * ->withParticipants(...) + * ->withTitle(...) + * ->withType(...) + * ->withUnreadCount(...) + * ->withChatID(...) * ``` */ public function __construct() @@ -58,23 +262,354 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * + * @param Participants|ParticipantsShape $participants + * @param Type|value-of $type + * @param Capabilities|CapabilitiesShape|null $capabilities + * @param Draft|DraftShape|null $draft + * @param Reminder|ReminderShape|null $reminder + * @param Snooze|SnoozeShape|null $snooze * @param Status|value-of|null $status */ public static function with( + string $id, + string $accountID, + string $network, + Participants|array $participants, + string $title, + Type|string $type, + int $unreadCount, string $chatID, - Status|string|null $status = null + Capabilities|array|null $capabilities = null, + ?string $description = null, + Draft|array|null $draft = null, + ?string $imgURL = null, + ?bool $isArchived = null, + ?bool $isLowPriority = null, + ?bool $isMarkedUnread = null, + ?bool $isMuted = null, + ?bool $isPinned = null, + ?bool $isReadOnly = null, + ?\DateTimeInterface $lastActivity = null, + ?string $lastReadMessageSortKey = null, + ?string $localChatID = null, + ?int $messageExpirySeconds = null, + Reminder|array|null $reminder = null, + Snooze|array|null $snooze = null, + ?int $unreadMentionsCount = null, + Status|string|null $status = null, ): self { $self = new self; + $self['id'] = $id; + $self['accountID'] = $accountID; + $self['network'] = $network; + $self['participants'] = $participants; + $self['title'] = $title; + $self['type'] = $type; + $self['unreadCount'] = $unreadCount; $self['chatID'] = $chatID; + null !== $capabilities && $self['capabilities'] = $capabilities; + null !== $description && $self['description'] = $description; + null !== $draft && $self['draft'] = $draft; + null !== $imgURL && $self['imgURL'] = $imgURL; + null !== $isArchived && $self['isArchived'] = $isArchived; + null !== $isLowPriority && $self['isLowPriority'] = $isLowPriority; + null !== $isMarkedUnread && $self['isMarkedUnread'] = $isMarkedUnread; + null !== $isMuted && $self['isMuted'] = $isMuted; + null !== $isPinned && $self['isPinned'] = $isPinned; + null !== $isReadOnly && $self['isReadOnly'] = $isReadOnly; + null !== $lastActivity && $self['lastActivity'] = $lastActivity; + null !== $lastReadMessageSortKey && $self['lastReadMessageSortKey'] = $lastReadMessageSortKey; + null !== $localChatID && $self['localChatID'] = $localChatID; + null !== $messageExpirySeconds && $self['messageExpirySeconds'] = $messageExpirySeconds; + null !== $reminder && $self['reminder'] = $reminder; + null !== $snooze && $self['snooze'] = $snooze; + null !== $unreadMentionsCount && $self['unreadMentionsCount'] = $unreadMentionsCount; null !== $status && $self['status'] = $status; return $self; } /** - * Newly created chat ID. + * Unique identifier of the chat across Beeper. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * Account ID this chat belongs to. + */ + public function withAccountID(string $accountID): self + { + $self = clone $this; + $self['accountID'] = $accountID; + + return $self; + } + + /** + * Display-only human-readable account/network name. + */ + public function withNetwork(string $network): self + { + $self = clone $this; + $self['network'] = $network; + + return $self; + } + + /** + * Chat participants information. + * + * @param Participants|ParticipantsShape $participants + */ + public function withParticipants(Participants|array $participants): self + { + $self = clone $this; + $self['participants'] = $participants; + + return $self; + } + + /** + * Display title of the chat as computed by the client/server. + */ + public function withTitle(string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } + + /** + * Chat type: 'single' for direct messages, 'group' for group chats. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Number of unread messages. + */ + public function withUnreadCount(int $unreadCount): self + { + $self = clone $this; + $self['unreadCount'] = $unreadCount; + + return $self; + } + + /** + * Chat capabilities reported by the platform. + * + * @param Capabilities|CapabilitiesShape $capabilities + */ + public function withCapabilities(Capabilities|array $capabilities): self + { + $self = clone $this; + $self['capabilities'] = $capabilities; + + return $self; + } + + /** + * Group chat description/topic when available. + */ + public function withDescription(?string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * Current draft object for this chat, or null when no draft is set. + * + * @param Draft|DraftShape|null $draft + */ + public function withDraft(Draft|array|null $draft): self + { + $self = clone $this; + $self['draft'] = $draft; + + return $self; + } + + /** + * Local filesystem path to the chat avatar image when available. + */ + public function withImgURL(?string $imgURL): self + { + $self = clone $this; + $self['imgURL'] = $imgURL; + + return $self; + } + + /** + * True if chat is archived. + */ + public function withIsArchived(bool $isArchived): self + { + $self = clone $this; + $self['isArchived'] = $isArchived; + + return $self; + } + + /** + * True if chat is marked low priority. + */ + public function withIsLowPriority(bool $isLowPriority): self + { + $self = clone $this; + $self['isLowPriority'] = $isLowPriority; + + return $self; + } + + /** + * True if the chat was explicitly marked unread by the authenticated user. + */ + public function withIsMarkedUnread(bool $isMarkedUnread): self + { + $self = clone $this; + $self['isMarkedUnread'] = $isMarkedUnread; + + return $self; + } + + /** + * True if chat notifications are muted. + */ + public function withIsMuted(bool $isMuted): self + { + $self = clone $this; + $self['isMuted'] = $isMuted; + + return $self; + } + + /** + * True if chat is pinned. + */ + public function withIsPinned(bool $isPinned): self + { + $self = clone $this; + $self['isPinned'] = $isPinned; + + return $self; + } + + /** + * True if messages cannot be sent in this chat. + */ + public function withIsReadOnly(bool $isReadOnly): self + { + $self = clone $this; + $self['isReadOnly'] = $isReadOnly; + + return $self; + } + + /** + * Timestamp of last activity. + */ + public function withLastActivity(\DateTimeInterface $lastActivity): self + { + $self = clone $this; + $self['lastActivity'] = $lastActivity; + + return $self; + } + + /** + * Last read message sortKey. + */ + public function withLastReadMessageSortKey( + string $lastReadMessageSortKey + ): self { + $self = clone $this; + $self['lastReadMessageSortKey'] = $lastReadMessageSortKey; + + return $self; + } + + /** + * Local chat ID specific to this Beeper Desktop installation. + */ + public function withLocalChatID(?string $localChatID): self + { + $self = clone $this; + $self['localChatID'] = $localChatID; + + return $self; + } + + /** + * Disappearing-message timer in seconds when available. + */ + public function withMessageExpirySeconds(?int $messageExpirySeconds): self + { + $self = clone $this; + $self['messageExpirySeconds'] = $messageExpirySeconds; + + return $self; + } + + /** + * Current reminder for this chat, or null when no reminder is set. + * + * @param Reminder|ReminderShape|null $reminder + */ + public function withReminder(Reminder|array|null $reminder): self + { + $self = clone $this; + $self['reminder'] = $reminder; + + return $self; + } + + /** + * Current snooze state for this chat, or null when no snooze is set. + * + * @param Snooze|SnoozeShape|null $snooze + */ + public function withSnooze(Snooze|array|null $snooze): self + { + $self = clone $this; + $self['snooze'] = $snooze; + + return $self; + } + + /** + * Number of unread messages that mention the authenticated user or @room. + */ + public function withUnreadMentionsCount(int $unreadMentionsCount): self + { + $self = clone $this; + $self['unreadMentionsCount'] = $unreadMentionsCount; + + return $self; + } + + /** + * DEPRECATED - use id instead. Compatibility alias for older clients. */ public function withChatID(string $chatID): self { @@ -85,7 +620,7 @@ public function withChatID(string $chatID): self } /** - * Only returned in start mode. 'existing' means an existing chat was reused; 'created' means a new chat was created. + * DEPRECATED - legacy start-chat status for older clients. New clients should inspect the returned Chat instead. * * @param Status|value-of $status */ diff --git a/src/Chats/ChatNewResponse/Status.php b/src/Chats/ChatNewResponse/Status.php index 64fd131..8ecda0f 100644 --- a/src/Chats/ChatNewResponse/Status.php +++ b/src/Chats/ChatNewResponse/Status.php @@ -5,7 +5,9 @@ namespace BeeperDesktop\Chats\ChatNewResponse; /** - * Only returned in start mode. 'existing' means an existing chat was reused; 'created' means a new chat was created. + * DEPRECATED - legacy start-chat status for older clients. New clients should inspect the returned Chat instead. + * + * @deprecated */ enum Status: string { diff --git a/src/Chats/ChatRetrieveParams.php b/src/Chats/ChatRetrieveParams.php index c67f16c..09968b7 100644 --- a/src/Chats/ChatRetrieveParams.php +++ b/src/Chats/ChatRetrieveParams.php @@ -23,7 +23,7 @@ final class ChatRetrieveParams implements BaseModel use SdkParams; /** - * Maximum number of participants to return. Use -1 for all; otherwise 0–500. Defaults to all (-1). + * Maximum number of participants to return. Use -1 for all; otherwise 0-500. Defaults to 100. List and search endpoints return up to 20 participants per chat. */ #[Optional(nullable: true)] public ?int $maxParticipantCount; @@ -48,7 +48,7 @@ public static function with(?int $maxParticipantCount = null): self } /** - * Maximum number of participants to return. Use -1 for all; otherwise 0–500. Defaults to all (-1). + * Maximum number of participants to return. Use -1 for all; otherwise 0-500. Defaults to 100. List and search endpoints return up to 20 participants per chat. */ public function withMaxParticipantCount(?int $maxParticipantCount): self { diff --git a/src/Chats/ChatStartParams.php b/src/Chats/ChatStartParams.php index dad746c..57fa5ab 100644 --- a/src/Chats/ChatStartParams.php +++ b/src/Chats/ChatStartParams.php @@ -12,7 +12,7 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** - * Resolve a user/contact and open a direct chat. Reuses an existing direct chat when one is found. Available in Beeper Desktop v4.2.799+. + * Resolve a user/contact and open a direct chat. Reuses and returns an existing direct chat when one is found. Available in Beeper Desktop v4.2.808+. * * @see BeeperDesktop\Services\ChatsService::start() * diff --git a/src/Chats/ChatStartResponse.php b/src/Chats/ChatStartResponse.php index 0d3f44e..ce14fdf 100644 --- a/src/Chats/ChatStartResponse.php +++ b/src/Chats/ChatStartResponse.php @@ -4,6 +4,12 @@ namespace BeeperDesktop\Chats; +use BeeperDesktop\Chats\Chat\Capabilities; +use BeeperDesktop\Chats\Chat\Draft; +use BeeperDesktop\Chats\Chat\Participants; +use BeeperDesktop\Chats\Chat\Reminder; +use BeeperDesktop\Chats\Chat\Snooze; +use BeeperDesktop\Chats\Chat\Type; use BeeperDesktop\Chats\ChatStartResponse\Status; use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Attributes\Required; @@ -11,8 +17,39 @@ use BeeperDesktop\Core\Contracts\BaseModel; /** + * @phpstan-import-type ParticipantsShape from \BeeperDesktop\Chats\Chat\Participants + * @phpstan-import-type CapabilitiesShape from \BeeperDesktop\Chats\Chat\Capabilities + * @phpstan-import-type DraftShape from \BeeperDesktop\Chats\Chat\Draft + * @phpstan-import-type ReminderShape from \BeeperDesktop\Chats\Chat\Reminder + * @phpstan-import-type SnoozeShape from \BeeperDesktop\Chats\Chat\Snooze + * * @phpstan-type ChatStartResponseShape = array{ - * chatID: string, status?: null|Status|value-of + * id: string, + * accountID: string, + * network: string, + * participants: Participants|ParticipantsShape, + * title: string, + * type: Type|value-of, + * unreadCount: int, + * capabilities?: null|Capabilities|CapabilitiesShape, + * description?: string|null, + * draft?: null|Draft|DraftShape, + * imgURL?: string|null, + * isArchived?: bool|null, + * isLowPriority?: bool|null, + * isMarkedUnread?: bool|null, + * isMuted?: bool|null, + * isPinned?: bool|null, + * isReadOnly?: bool|null, + * lastActivity?: \DateTimeInterface|null, + * lastReadMessageSortKey?: string|null, + * localChatID?: string|null, + * messageExpirySeconds?: int|null, + * reminder?: null|Reminder|ReminderShape, + * snooze?: null|Snooze|SnoozeShape, + * unreadMentionsCount?: int|null, + * chatID: string, + * status?: null|Status|value-of, * } */ final class ChatStartResponse implements BaseModel @@ -21,13 +58,163 @@ final class ChatStartResponse implements BaseModel use SdkModel; /** - * Newly created chat ID. + * Unique identifier of the chat across Beeper. + */ + #[Required] + public string $id; + + /** + * Account ID this chat belongs to. + */ + #[Required] + public string $accountID; + + /** + * Display-only human-readable account/network name. + */ + #[Required] + public string $network; + + /** + * Chat participants information. + */ + #[Required] + public Participants $participants; + + /** + * Display title of the chat as computed by the client/server. + */ + #[Required] + public string $title; + + /** + * Chat type: 'single' for direct messages, 'group' for group chats. + * + * @var value-of $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * Number of unread messages. + */ + #[Required] + public int $unreadCount; + + /** + * Chat capabilities reported by the platform. + */ + #[Optional] + public ?Capabilities $capabilities; + + /** + * Group chat description/topic when available. + */ + #[Optional(nullable: true)] + public ?string $description; + + /** + * Current draft object for this chat, or null when no draft is set. + */ + #[Optional(nullable: true)] + public ?Draft $draft; + + /** + * Local filesystem path to the chat avatar image when available. + */ + #[Optional(nullable: true)] + public ?string $imgURL; + + /** + * True if chat is archived. + */ + #[Optional] + public ?bool $isArchived; + + /** + * True if chat is marked low priority. + */ + #[Optional] + public ?bool $isLowPriority; + + /** + * True if the chat was explicitly marked unread by the authenticated user. + */ + #[Optional] + public ?bool $isMarkedUnread; + + /** + * True if chat notifications are muted. + */ + #[Optional] + public ?bool $isMuted; + + /** + * True if chat is pinned. + */ + #[Optional] + public ?bool $isPinned; + + /** + * True if messages cannot be sent in this chat. + */ + #[Optional] + public ?bool $isReadOnly; + + /** + * Timestamp of last activity. + */ + #[Optional] + public ?\DateTimeInterface $lastActivity; + + /** + * Last read message sortKey. + */ + #[Optional] + public ?string $lastReadMessageSortKey; + + /** + * Local chat ID specific to this Beeper Desktop installation. + */ + #[Optional(nullable: true)] + public ?string $localChatID; + + /** + * Disappearing-message timer in seconds when available. + */ + #[Optional(nullable: true)] + public ?int $messageExpirySeconds; + + /** + * Current reminder for this chat, or null when no reminder is set. + */ + #[Optional(nullable: true)] + public ?Reminder $reminder; + + /** + * Current snooze state for this chat, or null when no snooze is set. + */ + #[Optional(nullable: true)] + public ?Snooze $snooze; + + /** + * Number of unread messages that mention the authenticated user or @room. + */ + #[Optional] + public ?int $unreadMentionsCount; + + /** + * @deprecated + * + * DEPRECATED - use id instead. Compatibility alias for older clients. */ #[Required] public string $chatID; /** - * Only returned in start mode. 'existing' means an existing chat was reused; 'created' means a new chat was created. + * @deprecated + * + * DEPRECATED - legacy start-chat status for older clients. New clients should inspect the returned Chat instead. * * @var value-of|null $status */ @@ -39,13 +226,30 @@ final class ChatStartResponse implements BaseModel * * To enforce required parameters use * ``` - * ChatStartResponse::with(chatID: ...) + * ChatStartResponse::with( + * id: ..., + * accountID: ..., + * network: ..., + * participants: ..., + * title: ..., + * type: ..., + * unreadCount: ..., + * chatID: ..., + * ) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new ChatStartResponse)->withChatID(...) + * (new ChatStartResponse) + * ->withID(...) + * ->withAccountID(...) + * ->withNetwork(...) + * ->withParticipants(...) + * ->withTitle(...) + * ->withType(...) + * ->withUnreadCount(...) + * ->withChatID(...) * ``` */ public function __construct() @@ -58,23 +262,354 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. * + * @param Participants|ParticipantsShape $participants + * @param Type|value-of $type + * @param Capabilities|CapabilitiesShape|null $capabilities + * @param Draft|DraftShape|null $draft + * @param Reminder|ReminderShape|null $reminder + * @param Snooze|SnoozeShape|null $snooze * @param Status|value-of|null $status */ public static function with( + string $id, + string $accountID, + string $network, + Participants|array $participants, + string $title, + Type|string $type, + int $unreadCount, string $chatID, - Status|string|null $status = null + Capabilities|array|null $capabilities = null, + ?string $description = null, + Draft|array|null $draft = null, + ?string $imgURL = null, + ?bool $isArchived = null, + ?bool $isLowPriority = null, + ?bool $isMarkedUnread = null, + ?bool $isMuted = null, + ?bool $isPinned = null, + ?bool $isReadOnly = null, + ?\DateTimeInterface $lastActivity = null, + ?string $lastReadMessageSortKey = null, + ?string $localChatID = null, + ?int $messageExpirySeconds = null, + Reminder|array|null $reminder = null, + Snooze|array|null $snooze = null, + ?int $unreadMentionsCount = null, + Status|string|null $status = null, ): self { $self = new self; + $self['id'] = $id; + $self['accountID'] = $accountID; + $self['network'] = $network; + $self['participants'] = $participants; + $self['title'] = $title; + $self['type'] = $type; + $self['unreadCount'] = $unreadCount; $self['chatID'] = $chatID; + null !== $capabilities && $self['capabilities'] = $capabilities; + null !== $description && $self['description'] = $description; + null !== $draft && $self['draft'] = $draft; + null !== $imgURL && $self['imgURL'] = $imgURL; + null !== $isArchived && $self['isArchived'] = $isArchived; + null !== $isLowPriority && $self['isLowPriority'] = $isLowPriority; + null !== $isMarkedUnread && $self['isMarkedUnread'] = $isMarkedUnread; + null !== $isMuted && $self['isMuted'] = $isMuted; + null !== $isPinned && $self['isPinned'] = $isPinned; + null !== $isReadOnly && $self['isReadOnly'] = $isReadOnly; + null !== $lastActivity && $self['lastActivity'] = $lastActivity; + null !== $lastReadMessageSortKey && $self['lastReadMessageSortKey'] = $lastReadMessageSortKey; + null !== $localChatID && $self['localChatID'] = $localChatID; + null !== $messageExpirySeconds && $self['messageExpirySeconds'] = $messageExpirySeconds; + null !== $reminder && $self['reminder'] = $reminder; + null !== $snooze && $self['snooze'] = $snooze; + null !== $unreadMentionsCount && $self['unreadMentionsCount'] = $unreadMentionsCount; null !== $status && $self['status'] = $status; return $self; } /** - * Newly created chat ID. + * Unique identifier of the chat across Beeper. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * Account ID this chat belongs to. + */ + public function withAccountID(string $accountID): self + { + $self = clone $this; + $self['accountID'] = $accountID; + + return $self; + } + + /** + * Display-only human-readable account/network name. + */ + public function withNetwork(string $network): self + { + $self = clone $this; + $self['network'] = $network; + + return $self; + } + + /** + * Chat participants information. + * + * @param Participants|ParticipantsShape $participants + */ + public function withParticipants(Participants|array $participants): self + { + $self = clone $this; + $self['participants'] = $participants; + + return $self; + } + + /** + * Display title of the chat as computed by the client/server. + */ + public function withTitle(string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } + + /** + * Chat type: 'single' for direct messages, 'group' for group chats. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Number of unread messages. + */ + public function withUnreadCount(int $unreadCount): self + { + $self = clone $this; + $self['unreadCount'] = $unreadCount; + + return $self; + } + + /** + * Chat capabilities reported by the platform. + * + * @param Capabilities|CapabilitiesShape $capabilities + */ + public function withCapabilities(Capabilities|array $capabilities): self + { + $self = clone $this; + $self['capabilities'] = $capabilities; + + return $self; + } + + /** + * Group chat description/topic when available. + */ + public function withDescription(?string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * Current draft object for this chat, or null when no draft is set. + * + * @param Draft|DraftShape|null $draft + */ + public function withDraft(Draft|array|null $draft): self + { + $self = clone $this; + $self['draft'] = $draft; + + return $self; + } + + /** + * Local filesystem path to the chat avatar image when available. + */ + public function withImgURL(?string $imgURL): self + { + $self = clone $this; + $self['imgURL'] = $imgURL; + + return $self; + } + + /** + * True if chat is archived. + */ + public function withIsArchived(bool $isArchived): self + { + $self = clone $this; + $self['isArchived'] = $isArchived; + + return $self; + } + + /** + * True if chat is marked low priority. + */ + public function withIsLowPriority(bool $isLowPriority): self + { + $self = clone $this; + $self['isLowPriority'] = $isLowPriority; + + return $self; + } + + /** + * True if the chat was explicitly marked unread by the authenticated user. + */ + public function withIsMarkedUnread(bool $isMarkedUnread): self + { + $self = clone $this; + $self['isMarkedUnread'] = $isMarkedUnread; + + return $self; + } + + /** + * True if chat notifications are muted. + */ + public function withIsMuted(bool $isMuted): self + { + $self = clone $this; + $self['isMuted'] = $isMuted; + + return $self; + } + + /** + * True if chat is pinned. + */ + public function withIsPinned(bool $isPinned): self + { + $self = clone $this; + $self['isPinned'] = $isPinned; + + return $self; + } + + /** + * True if messages cannot be sent in this chat. + */ + public function withIsReadOnly(bool $isReadOnly): self + { + $self = clone $this; + $self['isReadOnly'] = $isReadOnly; + + return $self; + } + + /** + * Timestamp of last activity. + */ + public function withLastActivity(\DateTimeInterface $lastActivity): self + { + $self = clone $this; + $self['lastActivity'] = $lastActivity; + + return $self; + } + + /** + * Last read message sortKey. + */ + public function withLastReadMessageSortKey( + string $lastReadMessageSortKey + ): self { + $self = clone $this; + $self['lastReadMessageSortKey'] = $lastReadMessageSortKey; + + return $self; + } + + /** + * Local chat ID specific to this Beeper Desktop installation. + */ + public function withLocalChatID(?string $localChatID): self + { + $self = clone $this; + $self['localChatID'] = $localChatID; + + return $self; + } + + /** + * Disappearing-message timer in seconds when available. + */ + public function withMessageExpirySeconds(?int $messageExpirySeconds): self + { + $self = clone $this; + $self['messageExpirySeconds'] = $messageExpirySeconds; + + return $self; + } + + /** + * Current reminder for this chat, or null when no reminder is set. + * + * @param Reminder|ReminderShape|null $reminder + */ + public function withReminder(Reminder|array|null $reminder): self + { + $self = clone $this; + $self['reminder'] = $reminder; + + return $self; + } + + /** + * Current snooze state for this chat, or null when no snooze is set. + * + * @param Snooze|SnoozeShape|null $snooze + */ + public function withSnooze(Snooze|array|null $snooze): self + { + $self = clone $this; + $self['snooze'] = $snooze; + + return $self; + } + + /** + * Number of unread messages that mention the authenticated user or @room. + */ + public function withUnreadMentionsCount(int $unreadMentionsCount): self + { + $self = clone $this; + $self['unreadMentionsCount'] = $unreadMentionsCount; + + return $self; + } + + /** + * DEPRECATED - use id instead. Compatibility alias for older clients. */ public function withChatID(string $chatID): self { @@ -85,7 +620,7 @@ public function withChatID(string $chatID): self } /** - * Only returned in start mode. 'existing' means an existing chat was reused; 'created' means a new chat was created. + * DEPRECATED - legacy start-chat status for older clients. New clients should inspect the returned Chat instead. * * @param Status|value-of $status */ diff --git a/src/Chats/ChatStartResponse/Status.php b/src/Chats/ChatStartResponse/Status.php index 88baf8e..4900cf2 100644 --- a/src/Chats/ChatStartResponse/Status.php +++ b/src/Chats/ChatStartResponse/Status.php @@ -5,7 +5,9 @@ namespace BeeperDesktop\Chats\ChatStartResponse; /** - * Only returned in start mode. 'existing' means an existing chat was reused; 'created' means a new chat was created. + * DEPRECATED - legacy start-chat status for older clients. New clients should inspect the returned Chat instead. + * + * @deprecated */ enum Status: string { diff --git a/src/Chats/ChatUpdateParams.php b/src/Chats/ChatUpdateParams.php new file mode 100644 index 0000000..7223686 --- /dev/null +++ b/src/Chats/ChatUpdateParams.php @@ -0,0 +1,230 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Group chat description/topic. Support depends on the chat account and chat permissions. + */ + #[Optional(nullable: true)] + public ?string $description; + + /** + * Draft object to set or clear. Non-empty drafts are only accepted when the current draft is empty. Send draft=null to clear text and attachments together before setting a new draft. + */ + #[Optional(nullable: true)] + public ?Draft $draft; + + /** + * Local filesystem path to a group chat avatar image. Support depends on the chat account and chat permissions. + */ + #[Optional(nullable: true)] + public ?string $imgURL; + + /** + * Archive or unarchive the chat. + */ + #[Optional] + public ?bool $isArchived; + + /** + * Mark or unmark the chat as low priority when supported by the account. + */ + #[Optional] + public ?bool $isLowPriority; + + /** + * Mute or unmute the chat. + */ + #[Optional] + public ?bool $isMuted; + + /** + * Pin or unpin the chat when supported by the account. + */ + #[Optional] + public ?bool $isPinned; + + /** + * Disappearing-message timer in seconds, or null to clear when supported. + */ + #[Optional(nullable: true)] + public ?int $messageExpirySeconds; + + /** + * Custom chat title. Support depends on the chat account and chat permissions. + */ + #[Optional(nullable: true)] + public ?string $title; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Draft|DraftShape|null $draft + */ + public static function with( + ?string $description = null, + Draft|array|null $draft = null, + ?string $imgURL = null, + ?bool $isArchived = null, + ?bool $isLowPriority = null, + ?bool $isMuted = null, + ?bool $isPinned = null, + ?int $messageExpirySeconds = null, + ?string $title = null, + ): self { + $self = new self; + + null !== $description && $self['description'] = $description; + null !== $draft && $self['draft'] = $draft; + null !== $imgURL && $self['imgURL'] = $imgURL; + null !== $isArchived && $self['isArchived'] = $isArchived; + null !== $isLowPriority && $self['isLowPriority'] = $isLowPriority; + null !== $isMuted && $self['isMuted'] = $isMuted; + null !== $isPinned && $self['isPinned'] = $isPinned; + null !== $messageExpirySeconds && $self['messageExpirySeconds'] = $messageExpirySeconds; + null !== $title && $self['title'] = $title; + + return $self; + } + + /** + * Group chat description/topic. Support depends on the chat account and chat permissions. + */ + public function withDescription(?string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * Draft object to set or clear. Non-empty drafts are only accepted when the current draft is empty. Send draft=null to clear text and attachments together before setting a new draft. + * + * @param Draft|DraftShape|null $draft + */ + public function withDraft(Draft|array|null $draft): self + { + $self = clone $this; + $self['draft'] = $draft; + + return $self; + } + + /** + * Local filesystem path to a group chat avatar image. Support depends on the chat account and chat permissions. + */ + public function withImgURL(?string $imgURL): self + { + $self = clone $this; + $self['imgURL'] = $imgURL; + + return $self; + } + + /** + * Archive or unarchive the chat. + */ + public function withIsArchived(bool $isArchived): self + { + $self = clone $this; + $self['isArchived'] = $isArchived; + + return $self; + } + + /** + * Mark or unmark the chat as low priority when supported by the account. + */ + public function withIsLowPriority(bool $isLowPriority): self + { + $self = clone $this; + $self['isLowPriority'] = $isLowPriority; + + return $self; + } + + /** + * Mute or unmute the chat. + */ + public function withIsMuted(bool $isMuted): self + { + $self = clone $this; + $self['isMuted'] = $isMuted; + + return $self; + } + + /** + * Pin or unpin the chat when supported by the account. + */ + public function withIsPinned(bool $isPinned): self + { + $self = clone $this; + $self['isPinned'] = $isPinned; + + return $self; + } + + /** + * Disappearing-message timer in seconds, or null to clear when supported. + */ + public function withMessageExpirySeconds(?int $messageExpirySeconds): self + { + $self = clone $this; + $self['messageExpirySeconds'] = $messageExpirySeconds; + + return $self; + } + + /** + * Custom chat title. Support depends on the chat account and chat permissions. + */ + public function withTitle(?string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } +} diff --git a/src/Chats/ChatUpdateParams/Draft.php b/src/Chats/ChatUpdateParams/Draft.php new file mode 100644 index 0000000..51f926a --- /dev/null +++ b/src/Chats/ChatUpdateParams/Draft.php @@ -0,0 +1,101 @@ +|null + * } + */ +final class Draft implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Draft text. Plain text and Markdown are converted to Matrix HTML with the same rules used by send and edit. + */ + #[Required] + public string $text; + + /** + * Draft attachments keyed by attachment ID. Each attachment must reference an uploadID returned by the upload file endpoint. + * + * @var array|null $attachments + */ + #[Optional(map: Attachment::class)] + public ?array $attachments; + + /** + * `new Draft()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Draft::with(text: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Draft)->withText(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param array|null $attachments + */ + public static function with(string $text, ?array $attachments = null): self + { + $self = new self; + + $self['text'] = $text; + + null !== $attachments && $self['attachments'] = $attachments; + + return $self; + } + + /** + * Draft text. Plain text and Markdown are converted to Matrix HTML with the same rules used by send and edit. + */ + public function withText(string $text): self + { + $self = clone $this; + $self['text'] = $text; + + return $self; + } + + /** + * Draft attachments keyed by attachment ID. Each attachment must reference an uploadID returned by the upload file endpoint. + * + * @param array $attachments + */ + public function withAttachments(array $attachments): self + { + $self = clone $this; + $self['attachments'] = $attachments; + + return $self; + } +} diff --git a/src/Chats/ChatUpdateParams/Draft/Attachment.php b/src/Chats/ChatUpdateParams/Draft/Attachment.php new file mode 100644 index 0000000..2482277 --- /dev/null +++ b/src/Chats/ChatUpdateParams/Draft/Attachment.php @@ -0,0 +1,206 @@ +, + * } + */ +final class Attachment implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Upload ID from uploadAsset endpoint. Required to reference uploaded files. + */ + #[Required] + public string $uploadID; + + /** + * Optional draft attachment identifier. If omitted, a new identifier is generated. + */ + #[Optional] + public ?string $id; + + /** + * Duration in seconds (optional override of cached value). + */ + #[Optional] + public ?float $duration; + + /** + * Filename (optional override of cached value). + */ + #[Optional] + public ?string $fileName; + + /** + * MIME type (optional override of cached value). + */ + #[Optional] + public ?string $mimeType; + + /** + * Dimensions (optional override of cached value). + */ + #[Optional] + public ?Size $size; + + /** + * Attachment type hint (image, video, audio, file, gif, voice-note, sticker). If omitted, auto-detected from mimeType. + * + * @var value-of|null $type + */ + #[Optional(enum: Type::class)] + public ?string $type; + + /** + * `new Attachment()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Attachment::with(uploadID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Attachment)->withUploadID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Size|SizeShape|null $size + * @param Type|value-of|null $type + */ + public static function with( + string $uploadID, + ?string $id = null, + ?float $duration = null, + ?string $fileName = null, + ?string $mimeType = null, + Size|array|null $size = null, + Type|string|null $type = null, + ): self { + $self = new self; + + $self['uploadID'] = $uploadID; + + null !== $id && $self['id'] = $id; + null !== $duration && $self['duration'] = $duration; + null !== $fileName && $self['fileName'] = $fileName; + null !== $mimeType && $self['mimeType'] = $mimeType; + null !== $size && $self['size'] = $size; + null !== $type && $self['type'] = $type; + + return $self; + } + + /** + * Upload ID from uploadAsset endpoint. Required to reference uploaded files. + */ + public function withUploadID(string $uploadID): self + { + $self = clone $this; + $self['uploadID'] = $uploadID; + + return $self; + } + + /** + * Optional draft attachment identifier. If omitted, a new identifier is generated. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * Duration in seconds (optional override of cached value). + */ + public function withDuration(float $duration): self + { + $self = clone $this; + $self['duration'] = $duration; + + return $self; + } + + /** + * Filename (optional override of cached value). + */ + public function withFileName(string $fileName): self + { + $self = clone $this; + $self['fileName'] = $fileName; + + return $self; + } + + /** + * MIME type (optional override of cached value). + */ + public function withMimeType(string $mimeType): self + { + $self = clone $this; + $self['mimeType'] = $mimeType; + + return $self; + } + + /** + * Dimensions (optional override of cached value). + * + * @param Size|SizeShape $size + */ + public function withSize(Size|array $size): self + { + $self = clone $this; + $self['size'] = $size; + + return $self; + } + + /** + * Attachment type hint (image, video, audio, file, gif, voice-note, sticker). If omitted, auto-detected from mimeType. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } +} diff --git a/src/Chats/ChatUpdateParams/Draft/Attachment/Size.php b/src/Chats/ChatUpdateParams/Draft/Attachment/Size.php new file mode 100644 index 0000000..269be18 --- /dev/null +++ b/src/Chats/ChatUpdateParams/Draft/Attachment/Size.php @@ -0,0 +1,76 @@ + */ + use SdkModel; + + #[Required] + public float $height; + + #[Required] + public float $width; + + /** + * `new Size()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Size::with(height: ..., width: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Size)->withHeight(...)->withWidth(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(float $height, float $width): self + { + $self = new self; + + $self['height'] = $height; + $self['width'] = $width; + + return $self; + } + + public function withHeight(float $height): self + { + $self = clone $this; + $self['height'] = $height; + + return $self; + } + + public function withWidth(float $width): self + { + $self = clone $this; + $self['width'] = $width; + + return $self; + } +} diff --git a/src/Chats/ChatUpdateParams/Draft/Attachment/Type.php b/src/Chats/ChatUpdateParams/Draft/Attachment/Type.php new file mode 100644 index 0000000..a4ece19 --- /dev/null +++ b/src/Chats/ChatUpdateParams/Draft/Attachment/Type.php @@ -0,0 +1,25 @@ +withChatID(...)->withReactionKey(...) + * (new ReactionDeleteParams)->withChatID(...)->withMessageID(...) * ``` */ public function __construct() @@ -60,18 +60,18 @@ public function __construct() * * You must use named parameters to construct any parameters with a default value. */ - public static function with(string $chatID, string $reactionKey): self + public static function with(string $chatID, string $messageID): self { $self = new self; $self['chatID'] = $chatID; - $self['reactionKey'] = $reactionKey; + $self['messageID'] = $messageID; return $self; } /** - * Unique identifier of the chat. + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ public function withChatID(string $chatID): self { @@ -82,12 +82,12 @@ public function withChatID(string $chatID): self } /** - * Reaction key to remove. + * Message ID. */ - public function withReactionKey(string $reactionKey): self + public function withMessageID(string $messageID): self { $self = clone $this; - $self['reactionKey'] = $reactionKey; + $self['messageID'] = $messageID; return $self; } diff --git a/src/Chats/Messages/Reactions/ReactionDeleteResponse.php b/src/Chats/Messages/Reactions/ReactionDeleteResponse.php index 3c431a5..4983aa2 100644 --- a/src/Chats/Messages/Reactions/ReactionDeleteResponse.php +++ b/src/Chats/Messages/Reactions/ReactionDeleteResponse.php @@ -19,13 +19,13 @@ final class ReactionDeleteResponse implements BaseModel use SdkModel; /** - * Whether the reaction was successfully removed. + * Always true. Indicates the reaction removal was queued; failures return an error response. */ #[Required] public bool $success = true; /** - * Unique identifier of the chat. + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ #[Required] public string $chatID; @@ -84,7 +84,7 @@ public static function with( } /** - * Unique identifier of the chat. + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ public function withChatID(string $chatID): self { @@ -117,7 +117,7 @@ public function withReactionKey(string $reactionKey): self } /** - * Whether the reaction was successfully removed. + * Always true. Indicates the reaction removal was queued; failures return an error response. */ public function withSuccess(bool $success): self { diff --git a/src/Chats/Reminders/ReminderCreateParams/Reminder.php b/src/Chats/Reminders/ReminderCreateParams/Reminder.php index 7d3510a..d6e3ff2 100644 --- a/src/Chats/Reminders/ReminderCreateParams/Reminder.php +++ b/src/Chats/Reminders/ReminderCreateParams/Reminder.php @@ -13,7 +13,7 @@ * Reminder configuration. * * @phpstan-type ReminderShape = array{ - * remindAtMs: float, dismissOnIncomingMessage?: bool|null + * remindAt: \DateTimeInterface, dismissOnIncomingMessage?: bool|null * } */ final class Reminder implements BaseModel @@ -22,10 +22,10 @@ final class Reminder implements BaseModel use SdkModel; /** - * Unix timestamp in milliseconds when reminder should trigger. + * Timestamp when the reminder should trigger. */ #[Required] - public float $remindAtMs; + public \DateTimeInterface $remindAt; /** * Cancel reminder if someone messages in the chat. @@ -38,13 +38,13 @@ final class Reminder implements BaseModel * * To enforce required parameters use * ``` - * Reminder::with(remindAtMs: ...) + * Reminder::with(remindAt: ...) * ``` * * Otherwise ensure the following setters are called * * ``` - * (new Reminder)->withRemindAtMs(...) + * (new Reminder)->withRemindAt(...) * ``` */ public function __construct() @@ -58,12 +58,12 @@ public function __construct() * You must use named parameters to construct any parameters with a default value. */ public static function with( - float $remindAtMs, + \DateTimeInterface $remindAt, ?bool $dismissOnIncomingMessage = null ): self { $self = new self; - $self['remindAtMs'] = $remindAtMs; + $self['remindAt'] = $remindAt; null !== $dismissOnIncomingMessage && $self['dismissOnIncomingMessage'] = $dismissOnIncomingMessage; @@ -71,12 +71,12 @@ public static function with( } /** - * Unix timestamp in milliseconds when reminder should trigger. + * Timestamp when the reminder should trigger. */ - public function withRemindAtMs(float $remindAtMs): self + public function withRemindAt(\DateTimeInterface $remindAt): self { $self = clone $this; - $self['remindAtMs'] = $remindAtMs; + $self['remindAt'] = $remindAt; return $self; } diff --git a/src/Client.php b/src/Client.php index 887e602..9806990 100644 --- a/src/Client.php +++ b/src/Client.php @@ -127,11 +127,11 @@ public function __construct( /** * @api * - * Focus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill draft text and attachment. + * Focus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill plain text and an image path. * * @param string $chatID Optional Beeper chat ID (or local chat ID) to focus after opening the app. If omitted, only opens/focuses the app. - * @param string $draftAttachmentPath optional draft attachment path to populate in the message input field - * @param string $draftText optional draft text to populate in the message input field + * @param string $draftAttachmentPath optional image path to populate in the message input field + * @param string $draftText optional plain text to populate in the message input field * @param string $messageID Optional message ID. Jumps to that message in the chat when opening. * @param RequestOpts|null $requestOptions * diff --git a/src/Info/InfoGetResponse/Server.php b/src/Info/InfoGetResponse/Server.php index 3fcf9b4..bcc6df9 100644 --- a/src/Info/InfoGetResponse/Server.php +++ b/src/Info/InfoGetResponse/Server.php @@ -24,7 +24,7 @@ final class Server implements BaseModel use SdkModel; /** - * Base URL of the Connect server. + * Base URL of the Beeper Desktop API server. */ #[Required('base_url')] public string $baseURL; @@ -117,7 +117,7 @@ public static function with( } /** - * Base URL of the Connect server. + * Base URL of the Beeper Desktop API server. */ public function withBaseURL(string $baseURL): self { diff --git a/src/Message.php b/src/Message.php index f1a8846..22187db 100644 --- a/src/Message.php +++ b/src/Message.php @@ -8,11 +8,18 @@ use BeeperDesktop\Core\Attributes\Required; use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Message\Link; +use BeeperDesktop\Message\Seen; +use BeeperDesktop\Message\SendStatus; use BeeperDesktop\Message\Type; /** + * @phpstan-import-type SeenVariants from \BeeperDesktop\Message\Seen * @phpstan-import-type AttachmentShape from \BeeperDesktop\Attachment + * @phpstan-import-type LinkShape from \BeeperDesktop\Message\Link * @phpstan-import-type ReactionShape from \BeeperDesktop\Reaction + * @phpstan-import-type SeenShape from \BeeperDesktop\Message\Seen + * @phpstan-import-type SendStatusShape from \BeeperDesktop\Message\SendStatus * * @phpstan-type MessageShape = array{ * id: string, @@ -22,11 +29,18 @@ * sortKey: string, * timestamp: \DateTimeInterface, * attachments?: list|null, + * editedTimestamp?: \DateTimeInterface|null, + * isDeleted?: bool|null, + * isHidden?: bool|null, * isSender?: bool|null, * isUnread?: bool|null, * linkedMessageID?: string|null, + * links?: list|null, + * mentions?: list|null, * reactions?: list|null, + * seen?: SeenShape|null, * senderName?: string|null, + * sendStatus?: null|SendStatus|SendStatusShape, * text?: string|null, * type?: null|Type|value-of, * } @@ -49,13 +63,13 @@ final class Message implements BaseModel public string $accountID; /** - * Unique identifier of the chat. + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ #[Required] public string $chatID; /** - * Sender user ID. + * Matrix-style fully-qualified sender user ID, usually including a bridge prefix and homeserver. */ #[Required] public string $senderID; @@ -80,6 +94,24 @@ final class Message implements BaseModel #[Optional(list: Attachment::class)] public ?array $attachments; + /** + * Timestamp when the message was edited, if known. + */ + #[Optional] + public ?\DateTimeInterface $editedTimestamp; + + /** + * True if the message has been deleted. + */ + #[Optional] + public ?bool $isDeleted; + + /** + * True if the message is hidden from normal display. + */ + #[Optional] + public ?bool $isHidden; + /** * True if the authenticated user sent the message. */ @@ -98,6 +130,22 @@ final class Message implements BaseModel #[Optional] public ?string $linkedMessageID; + /** + * Link previews included with this message, if any. + * + * @var list|null $links + */ + #[Optional(list: Link::class)] + public ?array $links; + + /** + * Mentioned user IDs, @room, or null for legacy messages that require text scanning. + * + * @var list|null $mentions + */ + #[Optional(list: 'string', nullable: true)] + public ?array $mentions; + /** * Reactions to the message, if any. * @@ -106,6 +154,14 @@ final class Message implements BaseModel #[Optional(list: Reaction::class)] public ?array $reactions; + /** + * Read receipt state for this message, when available. + * + * @var SeenVariants|null $seen + */ + #[Optional(union: Seen::class)] + public bool|\DateTimeInterface|array|null $seen; + /** * Resolved sender display name (impersonator/full name/username/participant name). */ @@ -113,7 +169,13 @@ final class Message implements BaseModel public ?string $senderName; /** - * Plain-text body if present. May include a JSON fallback with text entities for rich messages. + * Message send status for this message, when reported by the bridge. + */ + #[Optional] + public ?SendStatus $sendStatus; + + /** + * Matrix HTML body if present. */ #[Optional] public ?string $text; @@ -164,7 +226,11 @@ public function __construct() * You must use named parameters to construct any parameters with a default value. * * @param list|null $attachments + * @param list|null $links + * @param list|null $mentions * @param list|null $reactions + * @param SeenShape|null $seen + * @param SendStatus|SendStatusShape|null $sendStatus * @param Type|value-of|null $type */ public static function with( @@ -175,11 +241,18 @@ public static function with( string $sortKey, \DateTimeInterface $timestamp, ?array $attachments = null, + ?\DateTimeInterface $editedTimestamp = null, + ?bool $isDeleted = null, + ?bool $isHidden = null, ?bool $isSender = null, ?bool $isUnread = null, ?string $linkedMessageID = null, + ?array $links = null, + ?array $mentions = null, ?array $reactions = null, + bool|\DateTimeInterface|array|null $seen = null, ?string $senderName = null, + SendStatus|array|null $sendStatus = null, ?string $text = null, Type|string|null $type = null, ): self { @@ -193,11 +266,18 @@ public static function with( $self['timestamp'] = $timestamp; null !== $attachments && $self['attachments'] = $attachments; + null !== $editedTimestamp && $self['editedTimestamp'] = $editedTimestamp; + null !== $isDeleted && $self['isDeleted'] = $isDeleted; + null !== $isHidden && $self['isHidden'] = $isHidden; null !== $isSender && $self['isSender'] = $isSender; null !== $isUnread && $self['isUnread'] = $isUnread; null !== $linkedMessageID && $self['linkedMessageID'] = $linkedMessageID; + null !== $links && $self['links'] = $links; + null !== $mentions && $self['mentions'] = $mentions; null !== $reactions && $self['reactions'] = $reactions; + null !== $seen && $self['seen'] = $seen; null !== $senderName && $self['senderName'] = $senderName; + null !== $sendStatus && $self['sendStatus'] = $sendStatus; null !== $text && $self['text'] = $text; null !== $type && $self['type'] = $type; @@ -227,7 +307,7 @@ public function withAccountID(string $accountID): self } /** - * Unique identifier of the chat. + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ public function withChatID(string $chatID): self { @@ -238,7 +318,7 @@ public function withChatID(string $chatID): self } /** - * Sender user ID. + * Matrix-style fully-qualified sender user ID, usually including a bridge prefix and homeserver. */ public function withSenderID(string $senderID): self { @@ -283,6 +363,40 @@ public function withAttachments(array $attachments): self return $self; } + /** + * Timestamp when the message was edited, if known. + */ + public function withEditedTimestamp( + \DateTimeInterface $editedTimestamp + ): self { + $self = clone $this; + $self['editedTimestamp'] = $editedTimestamp; + + return $self; + } + + /** + * True if the message has been deleted. + */ + public function withIsDeleted(bool $isDeleted): self + { + $self = clone $this; + $self['isDeleted'] = $isDeleted; + + return $self; + } + + /** + * True if the message is hidden from normal display. + */ + public function withIsHidden(bool $isHidden): self + { + $self = clone $this; + $self['isHidden'] = $isHidden; + + return $self; + } + /** * True if the authenticated user sent the message. */ @@ -316,6 +430,32 @@ public function withLinkedMessageID(string $linkedMessageID): self return $self; } + /** + * Link previews included with this message, if any. + * + * @param list $links + */ + public function withLinks(array $links): self + { + $self = clone $this; + $self['links'] = $links; + + return $self; + } + + /** + * Mentioned user IDs, @room, or null for legacy messages that require text scanning. + * + * @param list|null $mentions + */ + public function withMentions(?array $mentions): self + { + $self = clone $this; + $self['mentions'] = $mentions; + + return $self; + } + /** * Reactions to the message, if any. * @@ -329,6 +469,19 @@ public function withReactions(array $reactions): self return $self; } + /** + * Read receipt state for this message, when available. + * + * @param SeenShape $seen + */ + public function withSeen(bool|\DateTimeInterface|array $seen): self + { + $self = clone $this; + $self['seen'] = $seen; + + return $self; + } + /** * Resolved sender display name (impersonator/full name/username/participant name). */ @@ -341,7 +494,20 @@ public function withSenderName(string $senderName): self } /** - * Plain-text body if present. May include a JSON fallback with text entities for rich messages. + * Message send status for this message, when reported by the bridge. + * + * @param SendStatus|SendStatusShape $sendStatus + */ + public function withSendStatus(SendStatus|array $sendStatus): self + { + $self = clone $this; + $self['sendStatus'] = $sendStatus; + + return $self; + } + + /** + * Matrix HTML body if present. */ public function withText(string $text): self { diff --git a/src/Message/Link.php b/src/Message/Link.php new file mode 100644 index 0000000..c41dfc5 --- /dev/null +++ b/src/Message/Link.php @@ -0,0 +1,202 @@ + */ + use SdkModel; + + /** + * Link preview title. + */ + #[Required] + public string $title; + + /** + * Resolved link URL. + */ + #[Required] + public string $url; + + /** + * Favicon URL if available. May be temporary or local-only to this device; download promptly if durable access is needed. + */ + #[Optional] + public ?string $favicon; + + /** + * Preview image URL if available. May be temporary or local-only to this device; download promptly if durable access is needed. + */ + #[Optional] + public ?string $img; + + /** + * Preview image dimensions. + */ + #[Optional] + public ?ImgSize $imgSize; + + /** + * Original URL when the displayed URL is shortened or redirected. + */ + #[Optional] + public ?string $originalURL; + + /** + * Link preview summary. + */ + #[Optional] + public ?string $summary; + + /** + * `new Link()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Link::with(title: ..., url: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Link)->withTitle(...)->withURL(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param ImgSize|ImgSizeShape|null $imgSize + */ + public static function with( + string $title, + string $url, + ?string $favicon = null, + ?string $img = null, + ImgSize|array|null $imgSize = null, + ?string $originalURL = null, + ?string $summary = null, + ): self { + $self = new self; + + $self['title'] = $title; + $self['url'] = $url; + + null !== $favicon && $self['favicon'] = $favicon; + null !== $img && $self['img'] = $img; + null !== $imgSize && $self['imgSize'] = $imgSize; + null !== $originalURL && $self['originalURL'] = $originalURL; + null !== $summary && $self['summary'] = $summary; + + return $self; + } + + /** + * Link preview title. + */ + public function withTitle(string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } + + /** + * Resolved link URL. + */ + public function withURL(string $url): self + { + $self = clone $this; + $self['url'] = $url; + + return $self; + } + + /** + * Favicon URL if available. May be temporary or local-only to this device; download promptly if durable access is needed. + */ + public function withFavicon(string $favicon): self + { + $self = clone $this; + $self['favicon'] = $favicon; + + return $self; + } + + /** + * Preview image URL if available. May be temporary or local-only to this device; download promptly if durable access is needed. + */ + public function withImg(string $img): self + { + $self = clone $this; + $self['img'] = $img; + + return $self; + } + + /** + * Preview image dimensions. + * + * @param ImgSize|ImgSizeShape $imgSize + */ + public function withImgSize(ImgSize|array $imgSize): self + { + $self = clone $this; + $self['imgSize'] = $imgSize; + + return $self; + } + + /** + * Original URL when the displayed URL is shortened or redirected. + */ + public function withOriginalURL(string $originalURL): self + { + $self = clone $this; + $self['originalURL'] = $originalURL; + + return $self; + } + + /** + * Link preview summary. + */ + public function withSummary(string $summary): self + { + $self = clone $this; + $self['summary'] = $summary; + + return $self; + } +} diff --git a/src/Message/Link/ImgSize.php b/src/Message/Link/ImgSize.php new file mode 100644 index 0000000..760bac4 --- /dev/null +++ b/src/Message/Link/ImgSize.php @@ -0,0 +1,62 @@ + */ + use SdkModel; + + #[Optional] + public ?float $height; + + #[Optional] + public ?float $width; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?float $height = null, ?float $width = null): self + { + $self = new self; + + null !== $height && $self['height'] = $height; + null !== $width && $self['width'] = $width; + + return $self; + } + + public function withHeight(float $height): self + { + $self = clone $this; + $self['height'] = $height; + + return $self; + } + + public function withWidth(float $width): self + { + $self = clone $this; + $self['width'] = $width; + + return $self; + } +} diff --git a/src/Message/Seen.php b/src/Message/Seen.php new file mode 100644 index 0000000..8a184c0 --- /dev/null +++ b/src/Message/Seen.php @@ -0,0 +1,34 @@ + + * @phpstan-type SeenShape = SeenVariants|array + */ +final class Seen implements ConverterSource +{ + use SdkUnion; + + /** + * @return list|array + */ + public static function variants(): array + { + return [ + 'bool', '\DateTimeInterface', new MapOf(MessageSeenByParticipant::class), + ]; + } +} diff --git a/src/Message/Seen/MessageSeenByParticipant.php b/src/Message/Seen/MessageSeenByParticipant.php new file mode 100644 index 0000000..720a57d --- /dev/null +++ b/src/Message/Seen/MessageSeenByParticipant.php @@ -0,0 +1,28 @@ +|array + */ + public static function variants(): array + { + return ['bool', '\DateTimeInterface']; + } +} diff --git a/src/Message/SendStatus.php b/src/Message/SendStatus.php new file mode 100644 index 0000000..8e93b4c --- /dev/null +++ b/src/Message/SendStatus.php @@ -0,0 +1,187 @@ +, + * timestamp: \DateTimeInterface, + * deliveredToUsers?: list|null, + * internalError?: string|null, + * message?: string|null, + * reason?: string|null, + * } + */ +final class SendStatus implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Current status of the message send attempt. + * + * @var value-of $status + */ + #[Required(enum: Status::class)] + public string $status; + + /** + * Timestamp for the send status event. + */ + #[Required] + public \DateTimeInterface $timestamp; + + /** + * User IDs the message was delivered to, when reported by the network. + * + * @var list|null $deliveredToUsers + */ + #[Optional(list: 'string')] + public ?array $deliveredToUsers; + + /** + * Internal bridge error detail. Intended for diagnostics, not end-user display. + */ + #[Optional] + public ?string $internalError; + + /** + * Human-readable send status or failure message. + */ + #[Optional] + public ?string $message; + + /** + * Machine-readable failure reason. Present when the send status is a failure. + */ + #[Optional] + public ?string $reason; + + /** + * `new SendStatus()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * SendStatus::with(status: ..., timestamp: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new SendStatus)->withStatus(...)->withTimestamp(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Status|value-of $status + * @param list|null $deliveredToUsers + */ + public static function with( + Status|string $status, + \DateTimeInterface $timestamp, + ?array $deliveredToUsers = null, + ?string $internalError = null, + ?string $message = null, + ?string $reason = null, + ): self { + $self = new self; + + $self['status'] = $status; + $self['timestamp'] = $timestamp; + + null !== $deliveredToUsers && $self['deliveredToUsers'] = $deliveredToUsers; + null !== $internalError && $self['internalError'] = $internalError; + null !== $message && $self['message'] = $message; + null !== $reason && $self['reason'] = $reason; + + return $self; + } + + /** + * Current status of the message send attempt. + * + * @param Status|value-of $status + */ + public function withStatus(Status|string $status): self + { + $self = clone $this; + $self['status'] = $status; + + return $self; + } + + /** + * Timestamp for the send status event. + */ + public function withTimestamp(\DateTimeInterface $timestamp): self + { + $self = clone $this; + $self['timestamp'] = $timestamp; + + return $self; + } + + /** + * User IDs the message was delivered to, when reported by the network. + * + * @param list $deliveredToUsers + */ + public function withDeliveredToUsers(array $deliveredToUsers): self + { + $self = clone $this; + $self['deliveredToUsers'] = $deliveredToUsers; + + return $self; + } + + /** + * Internal bridge error detail. Intended for diagnostics, not end-user display. + */ + public function withInternalError(string $internalError): self + { + $self = clone $this; + $self['internalError'] = $internalError; + + return $self; + } + + /** + * Human-readable send status or failure message. + */ + public function withMessage(string $message): self + { + $self = clone $this; + $self['message'] = $message; + + return $self; + } + + /** + * Machine-readable failure reason. Present when the send status is a failure. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/Message/SendStatus/Status.php b/src/Message/SendStatus/Status.php new file mode 100644 index 0000000..5c99941 --- /dev/null +++ b/src/Message/SendStatus/Status.php @@ -0,0 +1,19 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + */ + #[Required] + public string $chatID; + + /** + * True to request deletion for everyone when the network supports it; false to delete only for the authenticated user when supported. + */ + #[Optional(nullable: true)] + public ?bool $forEveryone; + + /** + * `new MessageDeleteParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * MessageDeleteParams::with(chatID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new MessageDeleteParams)->withChatID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $chatID, ?bool $forEveryone = null): self + { + $self = new self; + + $self['chatID'] = $chatID; + + null !== $forEveryone && $self['forEveryone'] = $forEveryone; + + return $self; + } + + /** + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + */ + public function withChatID(string $chatID): self + { + $self = clone $this; + $self['chatID'] = $chatID; + + return $self; + } + + /** + * True to request deletion for everyone when the network supports it; false to delete only for the authenticated user when supported. + */ + public function withForEveryone(?bool $forEveryone): self + { + $self = clone $this; + $self['forEveryone'] = $forEveryone; + + return $self; + } +} diff --git a/src/Messages/MessageRetrieveParams.php b/src/Messages/MessageRetrieveParams.php new file mode 100644 index 0000000..452ceec --- /dev/null +++ b/src/Messages/MessageRetrieveParams.php @@ -0,0 +1,74 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + */ + #[Required] + public string $chatID; + + /** + * `new MessageRetrieveParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * MessageRetrieveParams::with(chatID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new MessageRetrieveParams)->withChatID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $chatID): self + { + $self = new self; + + $self['chatID'] = $chatID; + + return $self; + } + + /** + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + */ + public function withChatID(string $chatID): self + { + $self = clone $this; + $self['chatID'] = $chatID; + + return $self; + } +} diff --git a/src/Messages/MessageSendParams.php b/src/Messages/MessageSendParams.php index 6c168c0..bc72b20 100644 --- a/src/Messages/MessageSendParams.php +++ b/src/Messages/MessageSendParams.php @@ -42,7 +42,7 @@ final class MessageSendParams implements BaseModel public ?string $replyToMessageID; /** - * Text content of the message you want to send. You may use markdown. + * Draft text. Plain text and Markdown are converted to Matrix HTML with the same rules used by send and edit. */ #[Optional] public ?string $text; @@ -98,7 +98,7 @@ public function withReplyToMessageID(string $replyToMessageID): self } /** - * Text content of the message you want to send. You may use markdown. + * Draft text. Plain text and Markdown are converted to Matrix HTML with the same rules used by send and edit. */ public function withText(string $text): self { diff --git a/src/Messages/MessageSendParams/Attachment.php b/src/Messages/MessageSendParams/Attachment.php index e217986..824b1d6 100644 --- a/src/Messages/MessageSendParams/Attachment.php +++ b/src/Messages/MessageSendParams/Attachment.php @@ -61,7 +61,7 @@ final class Attachment implements BaseModel public ?Size $size; /** - * Special attachment type (gif, voiceNote, sticker). If omitted, auto-detected from mimeType. + * Attachment type hint (image, video, audio, file, gif, voice-note, sticker). If omitted, auto-detected from mimeType. * * @var value-of|null $type */ @@ -174,7 +174,7 @@ public function withSize(Size|array $size): self } /** - * Special attachment type (gif, voiceNote, sticker). If omitted, auto-detected from mimeType. + * Attachment type hint (image, video, audio, file, gif, voice-note, sticker). If omitted, auto-detected from mimeType. * * @param Type|value-of $type */ diff --git a/src/Messages/MessageSendParams/Attachment/Type.php b/src/Messages/MessageSendParams/Attachment/Type.php index e11b46b..7f27b54 100644 --- a/src/Messages/MessageSendParams/Attachment/Type.php +++ b/src/Messages/MessageSendParams/Attachment/Type.php @@ -5,13 +5,21 @@ namespace BeeperDesktop\Messages\MessageSendParams\Attachment; /** - * Special attachment type (gif, voiceNote, sticker). If omitted, auto-detected from mimeType. + * Attachment type hint (image, video, audio, file, gif, voice-note, sticker). If omitted, auto-detected from mimeType. */ enum Type: string { + case IMAGE = 'image'; + + case VIDEO = 'video'; + + case AUDIO = 'audio'; + + case FILE = 'file'; + case GIF = 'gif'; - case VOICE_NOTE = 'voiceNote'; + case VOICE_NOTE = 'voice-note'; case STICKER = 'sticker'; } diff --git a/src/Messages/MessageSendResponse.php b/src/Messages/MessageSendResponse.php index e5cbdaa..b69de8b 100644 --- a/src/Messages/MessageSendResponse.php +++ b/src/Messages/MessageSendResponse.php @@ -19,13 +19,13 @@ final class MessageSendResponse implements BaseModel use SdkModel; /** - * Unique identifier of the chat. + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ #[Required] public string $chatID; /** - * Pending message ID. + * Pending ID assigned to the message before the network confirms the send. Pass it to GET /v1/chats/{chatID}/messages/{messageID} to resolve, or wait for the matching message.upserted over the WebSocket. */ #[Required] public string $pendingMessageID; @@ -65,7 +65,7 @@ public static function with(string $chatID, string $pendingMessageID): self } /** - * Unique identifier of the chat. + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ public function withChatID(string $chatID): self { @@ -76,7 +76,7 @@ public function withChatID(string $chatID): self } /** - * Pending message ID. + * Pending ID assigned to the message before the network confirms the send. Pass it to GET /v1/chats/{chatID}/messages/{messageID} to resolve, or wait for the matching message.upserted over the WebSocket. */ public function withPendingMessageID(string $pendingMessageID): self { diff --git a/src/Messages/MessageUpdateParams.php b/src/Messages/MessageUpdateParams.php index ccca067..9be3199 100644 --- a/src/Messages/MessageUpdateParams.php +++ b/src/Messages/MessageUpdateParams.php @@ -23,7 +23,7 @@ final class MessageUpdateParams implements BaseModel use SdkParams; /** - * Unique identifier of the chat. + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ #[Required] public string $chatID; @@ -69,7 +69,7 @@ public static function with(string $chatID, string $text): self } /** - * Unique identifier of the chat. + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ public function withChatID(string $chatID): self { diff --git a/src/Messages/MessageUpdateResponse.php b/src/Messages/MessageUpdateResponse.php index ad4b0ee..5fc82fd 100644 --- a/src/Messages/MessageUpdateResponse.php +++ b/src/Messages/MessageUpdateResponse.php @@ -4,13 +4,49 @@ namespace BeeperDesktop\Messages; +use BeeperDesktop\Attachment; +use BeeperDesktop\Core\Attributes\Optional; use BeeperDesktop\Core\Attributes\Required; use BeeperDesktop\Core\Concerns\SdkModel; use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Message\Link; +use BeeperDesktop\Message\Seen; +use BeeperDesktop\Message\SendStatus; +use BeeperDesktop\Message\Type; +use BeeperDesktop\Reaction; /** + * @phpstan-import-type SeenVariants from \BeeperDesktop\Message\Seen + * @phpstan-import-type AttachmentShape from \BeeperDesktop\Attachment + * @phpstan-import-type LinkShape from \BeeperDesktop\Message\Link + * @phpstan-import-type ReactionShape from \BeeperDesktop\Reaction + * @phpstan-import-type SeenShape from \BeeperDesktop\Message\Seen + * @phpstan-import-type SendStatusShape from \BeeperDesktop\Message\SendStatus + * * @phpstan-type MessageUpdateResponseShape = array{ - * chatID: string, messageID: string, success: bool + * id: string, + * accountID: string, + * chatID: string, + * senderID: string, + * sortKey: string, + * timestamp: \DateTimeInterface, + * attachments?: list|null, + * editedTimestamp?: \DateTimeInterface|null, + * isDeleted?: bool|null, + * isHidden?: bool|null, + * isSender?: bool|null, + * isUnread?: bool|null, + * linkedMessageID?: string|null, + * links?: list|null, + * mentions?: list|null, + * reactions?: list|null, + * seen?: SeenShape|null, + * senderName?: string|null, + * sendStatus?: null|SendStatus|SendStatusShape, + * text?: string|null, + * type?: null|Type|value-of, + * messageID: string, + * success: bool, * } */ final class MessageUpdateResponse implements BaseModel @@ -19,19 +55,155 @@ final class MessageUpdateResponse implements BaseModel use SdkModel; /** - * Unique identifier of the chat. + * Message ID. + */ + #[Required] + public string $id; + + /** + * Beeper account ID the message belongs to. + */ + #[Required] + public string $accountID; + + /** + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ #[Required] public string $chatID; /** - * Message ID. + * Matrix-style fully-qualified sender user ID, usually including a bridge prefix and homeserver. + */ + #[Required] + public string $senderID; + + /** + * A unique, sortable key used to sort messages. + */ + #[Required] + public string $sortKey; + + /** + * Message timestamp. + */ + #[Required] + public \DateTimeInterface $timestamp; + + /** + * Attachments included with this message, if any. + * + * @var list|null $attachments + */ + #[Optional(list: Attachment::class)] + public ?array $attachments; + + /** + * Timestamp when the message was edited, if known. + */ + #[Optional] + public ?\DateTimeInterface $editedTimestamp; + + /** + * True if the message has been deleted. + */ + #[Optional] + public ?bool $isDeleted; + + /** + * True if the message is hidden from normal display. + */ + #[Optional] + public ?bool $isHidden; + + /** + * True if the authenticated user sent the message. + */ + #[Optional] + public ?bool $isSender; + + /** + * True if the message is unread for the authenticated user. May be omitted. + */ + #[Optional] + public ?bool $isUnread; + + /** + * ID of the message this is a reply to, if any. + */ + #[Optional] + public ?string $linkedMessageID; + + /** + * Link previews included with this message, if any. + * + * @var list|null $links + */ + #[Optional(list: Link::class)] + public ?array $links; + + /** + * Mentioned user IDs, @room, or null for legacy messages that require text scanning. + * + * @var list|null $mentions + */ + #[Optional(list: 'string', nullable: true)] + public ?array $mentions; + + /** + * Reactions to the message, if any. + * + * @var list|null $reactions + */ + #[Optional(list: Reaction::class)] + public ?array $reactions; + + /** + * Read receipt state for this message, when available. + * + * @var SeenVariants|null $seen + */ + #[Optional(union: Seen::class)] + public bool|\DateTimeInterface|array|null $seen; + + /** + * Resolved sender display name (impersonator/full name/username/participant name). + */ + #[Optional] + public ?string $senderName; + + /** + * Message send status for this message, when reported by the bridge. + */ + #[Optional] + public ?SendStatus $sendStatus; + + /** + * Matrix HTML body if present. + */ + #[Optional] + public ?string $text; + + /** + * Message content type. Useful for distinguishing reactions, media messages, and state events from regular text messages. + * + * @var value-of|null $type + */ + #[Optional(enum: Type::class)] + public ?string $type; + + /** + * @deprecated + * + * DEPRECATED - use id instead. Compatibility alias for older clients. */ #[Required] public string $messageID; /** - * Whether the message was successfully edited. + * @deprecated + * + * DEPRECATED - compatibility field. Successful responses are already represented by the 200 status code. */ #[Required] public bool $success; @@ -41,14 +213,28 @@ final class MessageUpdateResponse implements BaseModel * * To enforce required parameters use * ``` - * MessageUpdateResponse::with(chatID: ..., messageID: ..., success: ...) + * MessageUpdateResponse::with( + * id: ..., + * accountID: ..., + * chatID: ..., + * senderID: ..., + * sortKey: ..., + * timestamp: ..., + * messageID: ..., + * success: ..., + * ) * ``` * * Otherwise ensure the following setters are called * * ``` * (new MessageUpdateResponse) + * ->withID(...) + * ->withAccountID(...) * ->withChatID(...) + * ->withSenderID(...) + * ->withSortKey(...) + * ->withTimestamp(...) * ->withMessageID(...) * ->withSuccess(...) * ``` @@ -62,23 +248,94 @@ public function __construct() * Construct an instance from the required parameters. * * You must use named parameters to construct any parameters with a default value. + * + * @param list|null $attachments + * @param list|null $links + * @param list|null $mentions + * @param list|null $reactions + * @param SeenShape|null $seen + * @param SendStatus|SendStatusShape|null $sendStatus + * @param Type|value-of|null $type */ public static function with( + string $id, + string $accountID, string $chatID, + string $senderID, + string $sortKey, + \DateTimeInterface $timestamp, string $messageID, - bool $success + bool $success, + ?array $attachments = null, + ?\DateTimeInterface $editedTimestamp = null, + ?bool $isDeleted = null, + ?bool $isHidden = null, + ?bool $isSender = null, + ?bool $isUnread = null, + ?string $linkedMessageID = null, + ?array $links = null, + ?array $mentions = null, + ?array $reactions = null, + bool|\DateTimeInterface|array|null $seen = null, + ?string $senderName = null, + SendStatus|array|null $sendStatus = null, + ?string $text = null, + Type|string|null $type = null, ): self { $self = new self; + $self['id'] = $id; + $self['accountID'] = $accountID; $self['chatID'] = $chatID; + $self['senderID'] = $senderID; + $self['sortKey'] = $sortKey; + $self['timestamp'] = $timestamp; $self['messageID'] = $messageID; $self['success'] = $success; + null !== $attachments && $self['attachments'] = $attachments; + null !== $editedTimestamp && $self['editedTimestamp'] = $editedTimestamp; + null !== $isDeleted && $self['isDeleted'] = $isDeleted; + null !== $isHidden && $self['isHidden'] = $isHidden; + null !== $isSender && $self['isSender'] = $isSender; + null !== $isUnread && $self['isUnread'] = $isUnread; + null !== $linkedMessageID && $self['linkedMessageID'] = $linkedMessageID; + null !== $links && $self['links'] = $links; + null !== $mentions && $self['mentions'] = $mentions; + null !== $reactions && $self['reactions'] = $reactions; + null !== $seen && $self['seen'] = $seen; + null !== $senderName && $self['senderName'] = $senderName; + null !== $sendStatus && $self['sendStatus'] = $sendStatus; + null !== $text && $self['text'] = $text; + null !== $type && $self['type'] = $type; + return $self; } /** - * Unique identifier of the chat. + * Message ID. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * Beeper account ID the message belongs to. + */ + public function withAccountID(string $accountID): self + { + $self = clone $this; + $self['accountID'] = $accountID; + + return $self; + } + + /** + * Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. */ public function withChatID(string $chatID): self { @@ -89,7 +346,220 @@ public function withChatID(string $chatID): self } /** - * Message ID. + * Matrix-style fully-qualified sender user ID, usually including a bridge prefix and homeserver. + */ + public function withSenderID(string $senderID): self + { + $self = clone $this; + $self['senderID'] = $senderID; + + return $self; + } + + /** + * A unique, sortable key used to sort messages. + */ + public function withSortKey(string $sortKey): self + { + $self = clone $this; + $self['sortKey'] = $sortKey; + + return $self; + } + + /** + * Message timestamp. + */ + public function withTimestamp(\DateTimeInterface $timestamp): self + { + $self = clone $this; + $self['timestamp'] = $timestamp; + + return $self; + } + + /** + * Attachments included with this message, if any. + * + * @param list $attachments + */ + public function withAttachments(array $attachments): self + { + $self = clone $this; + $self['attachments'] = $attachments; + + return $self; + } + + /** + * Timestamp when the message was edited, if known. + */ + public function withEditedTimestamp( + \DateTimeInterface $editedTimestamp + ): self { + $self = clone $this; + $self['editedTimestamp'] = $editedTimestamp; + + return $self; + } + + /** + * True if the message has been deleted. + */ + public function withIsDeleted(bool $isDeleted): self + { + $self = clone $this; + $self['isDeleted'] = $isDeleted; + + return $self; + } + + /** + * True if the message is hidden from normal display. + */ + public function withIsHidden(bool $isHidden): self + { + $self = clone $this; + $self['isHidden'] = $isHidden; + + return $self; + } + + /** + * True if the authenticated user sent the message. + */ + public function withIsSender(bool $isSender): self + { + $self = clone $this; + $self['isSender'] = $isSender; + + return $self; + } + + /** + * True if the message is unread for the authenticated user. May be omitted. + */ + public function withIsUnread(bool $isUnread): self + { + $self = clone $this; + $self['isUnread'] = $isUnread; + + return $self; + } + + /** + * ID of the message this is a reply to, if any. + */ + public function withLinkedMessageID(string $linkedMessageID): self + { + $self = clone $this; + $self['linkedMessageID'] = $linkedMessageID; + + return $self; + } + + /** + * Link previews included with this message, if any. + * + * @param list $links + */ + public function withLinks(array $links): self + { + $self = clone $this; + $self['links'] = $links; + + return $self; + } + + /** + * Mentioned user IDs, @room, or null for legacy messages that require text scanning. + * + * @param list|null $mentions + */ + public function withMentions(?array $mentions): self + { + $self = clone $this; + $self['mentions'] = $mentions; + + return $self; + } + + /** + * Reactions to the message, if any. + * + * @param list $reactions + */ + public function withReactions(array $reactions): self + { + $self = clone $this; + $self['reactions'] = $reactions; + + return $self; + } + + /** + * Read receipt state for this message, when available. + * + * @param SeenShape $seen + */ + public function withSeen(bool|\DateTimeInterface|array $seen): self + { + $self = clone $this; + $self['seen'] = $seen; + + return $self; + } + + /** + * Resolved sender display name (impersonator/full name/username/participant name). + */ + public function withSenderName(string $senderName): self + { + $self = clone $this; + $self['senderName'] = $senderName; + + return $self; + } + + /** + * Message send status for this message, when reported by the bridge. + * + * @param SendStatus|SendStatusShape $sendStatus + */ + public function withSendStatus(SendStatus|array $sendStatus): self + { + $self = clone $this; + $self['sendStatus'] = $sendStatus; + + return $self; + } + + /** + * Matrix HTML body if present. + */ + public function withText(string $text): self + { + $self = clone $this; + $self['text'] = $text; + + return $self; + } + + /** + * Message content type. Useful for distinguishing reactions, media messages, and state events from regular text messages. + * + * @param Type|value-of $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * DEPRECATED - use id instead. Compatibility alias for older clients. */ public function withMessageID(string $messageID): self { @@ -100,7 +570,7 @@ public function withMessageID(string $messageID): self } /** - * Whether the message was successfully edited. + * DEPRECATED - compatibility field. Successful responses are already represented by the 200 status code. */ public function withSuccess(bool $success): self { diff --git a/src/Reaction.php b/src/Reaction.php index a44defc..dd5bfd0 100644 --- a/src/Reaction.php +++ b/src/Reaction.php @@ -24,7 +24,7 @@ final class Reaction implements BaseModel use SdkModel; /** - * Reaction ID, typically ${participantID}${reactionKey} if multiple reactions allowed, or just participantID otherwise. + * Reaction ID. When a participant can react more than once, the ID is the participant ID concatenated with the reaction key; otherwise it equals the participant ID. */ #[Required] public string $id; @@ -97,7 +97,7 @@ public static function with( } /** - * Reaction ID, typically ${participantID}${reactionKey} if multiple reactions allowed, or just participantID otherwise. + * Reaction ID. When a participant can react more than once, the ID is the participant ID concatenated with the reaction key; otherwise it equals the participant ID. */ public function withID(string $id): self { diff --git a/src/ServiceContracts/AssetsContract.php b/src/ServiceContracts/AssetsContract.php index 029710d..325d0ce 100644 --- a/src/ServiceContracts/AssetsContract.php +++ b/src/ServiceContracts/AssetsContract.php @@ -19,7 +19,7 @@ interface AssetsContract /** * @api * - * @param string $url matrix content URL (mxc:// or localmxc://) for the asset to download + * @param string $url matrix content URL (mxc:// or localmxc://) for the file to download * @param RequestOpts|null $requestOptions * * @throws APIException @@ -32,7 +32,7 @@ public function download( /** * @api * - * @param string $url Asset URL to serve. Accepts mxc://, localmxc://, or file:// URLs. + * @param string $url File URL to serve. Accepts mxc://, localmxc://, or file:// URLs. * @param RequestOpts|null $requestOptions * * @throws APIException diff --git a/src/ServiceContracts/BeeperDesktopClientContract.php b/src/ServiceContracts/BeeperDesktopClientContract.php index d15413f..5886c42 100644 --- a/src/ServiceContracts/BeeperDesktopClientContract.php +++ b/src/ServiceContracts/BeeperDesktopClientContract.php @@ -18,8 +18,8 @@ interface BeeperDesktopClientContract * @api * * @param string $chatID Optional Beeper chat ID (or local chat ID) to focus after opening the app. If omitted, only opens/focuses the app. - * @param string $draftAttachmentPath optional draft attachment path to populate in the message input field - * @param string $draftText optional draft text to populate in the message input field + * @param string $draftAttachmentPath optional image path to populate in the message input field + * @param string $draftText optional plain text to populate in the message input field * @param string $messageID Optional message ID. Jumps to that message in the chat when opening. * @param RequestOpts|null $requestOptions * diff --git a/src/ServiceContracts/Chats/Messages/ReactionsContract.php b/src/ServiceContracts/Chats/Messages/ReactionsContract.php index df6d53e..aad62f2 100644 --- a/src/ServiceContracts/Chats/Messages/ReactionsContract.php +++ b/src/ServiceContracts/Chats/Messages/ReactionsContract.php @@ -17,27 +17,27 @@ interface ReactionsContract /** * @api * - * @param string $messageID Path param: ID of the message to remove a reaction from - * @param string $chatID path param: Unique identifier of the chat - * @param string $reactionKey Query param: Reaction key to remove + * @param string $reactionKey Reaction key to remove (emoji, shortcode, or custom emoji key) + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param string $messageID message ID * @param RequestOpts|null $requestOptions * * @throws APIException */ public function delete( - string $messageID, - string $chatID, string $reactionKey, + string $chatID, + string $messageID, RequestOptions|array|null $requestOptions = null, ): ReactionDeleteResponse; /** * @api * - * @param string $messageID Path param: ID of the message to add a reaction to - * @param string $chatID path param: Unique identifier of the chat + * @param string $messageID path param: Message ID + * @param string $chatID Path param: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param string $reactionKey Body param: Reaction key to add (emoji, shortcode, or custom emoji key) - * @param string $transactionID Body param: Optional transaction ID for deduplication and local echo tracking + * @param string $transactionID Body param: Optional transaction ID for deduplication and send tracking * @param RequestOpts|null $requestOptions * * @throws APIException diff --git a/src/ServiceContracts/Chats/Messages/ReactionsRawContract.php b/src/ServiceContracts/Chats/Messages/ReactionsRawContract.php index 463e43f..318d31a 100644 --- a/src/ServiceContracts/Chats/Messages/ReactionsRawContract.php +++ b/src/ServiceContracts/Chats/Messages/ReactionsRawContract.php @@ -20,7 +20,7 @@ interface ReactionsRawContract /** * @api * - * @param string $messageID Path param: ID of the message to remove a reaction from + * @param string $reactionKey Reaction key to remove (emoji, shortcode, or custom emoji key) * @param array|ReactionDeleteParams $params * @param RequestOpts|null $requestOptions * @@ -29,7 +29,7 @@ interface ReactionsRawContract * @throws APIException */ public function delete( - string $messageID, + string $reactionKey, array|ReactionDeleteParams $params, RequestOptions|array|null $requestOptions = null, ): BaseResponse; @@ -37,7 +37,7 @@ public function delete( /** * @api * - * @param string $messageID Path param: ID of the message to add a reaction to + * @param string $messageID path param: Message ID * @param array|ReactionAddParams $params * @param RequestOpts|null $requestOptions * diff --git a/src/ServiceContracts/Chats/RemindersContract.php b/src/ServiceContracts/Chats/RemindersContract.php index ee868dd..1e66144 100644 --- a/src/ServiceContracts/Chats/RemindersContract.php +++ b/src/ServiceContracts/Chats/RemindersContract.php @@ -17,7 +17,7 @@ interface RemindersContract /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param Reminder|ReminderShape $reminder Reminder configuration * @param RequestOpts|null $requestOptions * @@ -32,7 +32,7 @@ public function create( /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param RequestOpts|null $requestOptions * * @throws APIException diff --git a/src/ServiceContracts/Chats/RemindersRawContract.php b/src/ServiceContracts/Chats/RemindersRawContract.php index ba48a77..dbdea2a 100644 --- a/src/ServiceContracts/Chats/RemindersRawContract.php +++ b/src/ServiceContracts/Chats/RemindersRawContract.php @@ -17,7 +17,7 @@ interface RemindersRawContract /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array|ReminderCreateParams $params * @param RequestOpts|null $requestOptions * @@ -34,7 +34,7 @@ public function create( /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param RequestOpts|null $requestOptions * * @return BaseResponse diff --git a/src/ServiceContracts/ChatsContract.php b/src/ServiceContracts/ChatsContract.php index e3638ab..eeed273 100644 --- a/src/ServiceContracts/ChatsContract.php +++ b/src/ServiceContracts/ChatsContract.php @@ -13,12 +13,14 @@ use BeeperDesktop\Chats\ChatSearchParams\Scope; use BeeperDesktop\Chats\ChatStartParams\User; use BeeperDesktop\Chats\ChatStartResponse; +use BeeperDesktop\Chats\ChatUpdateParams\Draft; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; use BeeperDesktop\RequestOptions; /** + * @phpstan-import-type DraftShape from \BeeperDesktop\Chats\ChatUpdateParams\Draft * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatStartParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ @@ -48,15 +50,46 @@ public function create( /** * @api * - * @param string $chatID unique identifier of the chat - * @param int|null $maxParticipantCount Maximum number of participants to return. Use -1 for all; otherwise 0–500. Defaults to all (-1). + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param int|null $maxParticipantCount Maximum number of participants to return. Use -1 for all; otherwise 0-500. Defaults to 100. List and search endpoints return up to 20 participants per chat. * @param RequestOpts|null $requestOptions * * @throws APIException */ public function retrieve( string $chatID, - ?int $maxParticipantCount = -1, + ?int $maxParticipantCount = 100, + RequestOptions|array|null $requestOptions = null, + ): Chat; + + /** + * @api + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param string|null $description Group chat description/topic. Support depends on the chat account and chat permissions. + * @param Draft|DraftShape|null $draft Draft object to set or clear. Non-empty drafts are only accepted when the current draft is empty. Send draft=null to clear text and attachments together before setting a new draft. + * @param string|null $imgURL Local filesystem path to a group chat avatar image. Support depends on the chat account and chat permissions. + * @param bool $isArchived archive or unarchive the chat + * @param bool $isLowPriority mark or unmark the chat as low priority when supported by the account + * @param bool $isMuted mute or unmute the chat + * @param bool $isPinned pin or unpin the chat when supported by the account + * @param int|null $messageExpirySeconds disappearing-message timer in seconds, or null to clear when supported + * @param string|null $title Custom chat title. Support depends on the chat account and chat permissions. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function update( + string $chatID, + ?string $description = null, + Draft|array|null $draft = null, + ?string $imgURL = null, + ?bool $isArchived = null, + ?bool $isLowPriority = null, + ?bool $isMuted = null, + ?bool $isPinned = null, + ?int $messageExpirySeconds = null, + ?string $title = null, RequestOptions|array|null $requestOptions = null, ): Chat; @@ -82,7 +115,7 @@ public function list( /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param bool $archived True to archive, false to unarchive * @param RequestOpts|null $requestOptions * @@ -94,6 +127,49 @@ public function archive( RequestOptions|array|null $requestOptions = null, ): mixed; + /** + * @api + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param string $messageID optional message ID to mark read through + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function markRead( + string $chatID, + ?string $messageID = null, + RequestOptions|array|null $requestOptions = null, + ): Chat; + + /** + * @api + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param string $messageID optional message ID to mark unread from + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function markUnread( + string $chatID, + ?string $messageID = null, + RequestOptions|array|null $requestOptions = null, + ): Chat; + + /** + * @api + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function notifyAnyway( + string $chatID, + RequestOptions|array|null $requestOptions = null + ): Chat; + /** * @api * diff --git a/src/ServiceContracts/ChatsRawContract.php b/src/ServiceContracts/ChatsRawContract.php index 5c11e05..56770f6 100644 --- a/src/ServiceContracts/ChatsRawContract.php +++ b/src/ServiceContracts/ChatsRawContract.php @@ -9,11 +9,14 @@ use BeeperDesktop\Chats\ChatCreateParams; use BeeperDesktop\Chats\ChatListParams; use BeeperDesktop\Chats\ChatListResponse; +use BeeperDesktop\Chats\ChatMarkReadParams; +use BeeperDesktop\Chats\ChatMarkUnreadParams; use BeeperDesktop\Chats\ChatNewResponse; use BeeperDesktop\Chats\ChatRetrieveParams; use BeeperDesktop\Chats\ChatSearchParams; use BeeperDesktop\Chats\ChatStartParams; use BeeperDesktop\Chats\ChatStartResponse; +use BeeperDesktop\Chats\ChatUpdateParams; use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\CursorNoLimit; @@ -43,7 +46,7 @@ public function create( /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array|ChatRetrieveParams $params * @param RequestOpts|null $requestOptions * @@ -57,6 +60,23 @@ public function retrieve( RequestOptions|array|null $requestOptions = null, ): BaseResponse; + /** + * @api + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param array|ChatUpdateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function update( + string $chatID, + array|ChatUpdateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + /** * @api * @@ -75,7 +95,7 @@ public function list( /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array|ChatArchiveParams $params * @param RequestOpts|null $requestOptions * @@ -89,6 +109,55 @@ public function archive( RequestOptions|array|null $requestOptions = null, ): BaseResponse; + /** + * @api + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param array|ChatMarkReadParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function markRead( + string $chatID, + array|ChatMarkReadParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param array|ChatMarkUnreadParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function markUnread( + string $chatID, + array|ChatMarkUnreadParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function notifyAnyway( + string $chatID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; + /** * @api * diff --git a/src/ServiceContracts/MessagesContract.php b/src/ServiceContracts/MessagesContract.php index 66c79a4..c35650c 100644 --- a/src/ServiceContracts/MessagesContract.php +++ b/src/ServiceContracts/MessagesContract.php @@ -25,8 +25,23 @@ interface MessagesContract /** * @api * - * @param string $messageID Path param: ID of the message to edit - * @param string $chatID path param: Unique identifier of the chat + * @param string $messageID message ID + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieve( + string $messageID, + string $chatID, + RequestOptions|array|null $requestOptions = null, + ): Message; + + /** + * @api + * + * @param string $messageID path param: Message ID + * @param string $chatID Path param: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param string $text Body param: New text content for the message * @param RequestOpts|null $requestOptions * @@ -42,7 +57,7 @@ public function update( /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param string $cursor Opaque pagination cursor; do not inspect. Use together with 'direction'. * @param Direction|value-of $direction Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided. * @param RequestOpts|null $requestOptions @@ -58,6 +73,23 @@ public function list( RequestOptions|array|null $requestOptions = null, ): CursorNoLimit; + /** + * @api + * + * @param string $messageID path param: Message ID + * @param string $chatID Path param: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param bool|null $forEveryone query param: True to request deletion for everyone when the network supports it; false to delete only for the authenticated user when supported + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function delete( + string $messageID, + string $chatID, + ?bool $forEveryone = true, + RequestOptions|array|null $requestOptions = null, + ): mixed; + /** * @api * @@ -100,10 +132,10 @@ public function search( /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param Attachment|AttachmentShape $attachment Single attachment to send with the message * @param string $replyToMessageID Provide a message ID to send this as a reply to an existing message - * @param string $text Text content of the message you want to send. You may use markdown. + * @param string $text Draft text. Plain text and Markdown are converted to Matrix HTML with the same rules used by send and edit. * @param RequestOpts|null $requestOptions * * @throws APIException diff --git a/src/ServiceContracts/MessagesRawContract.php b/src/ServiceContracts/MessagesRawContract.php index 7a1c531..e27a6d7 100644 --- a/src/ServiceContracts/MessagesRawContract.php +++ b/src/ServiceContracts/MessagesRawContract.php @@ -9,7 +9,9 @@ use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; use BeeperDesktop\Message; +use BeeperDesktop\Messages\MessageDeleteParams; use BeeperDesktop\Messages\MessageListParams; +use BeeperDesktop\Messages\MessageRetrieveParams; use BeeperDesktop\Messages\MessageSearchParams; use BeeperDesktop\Messages\MessageSendParams; use BeeperDesktop\Messages\MessageSendResponse; @@ -25,7 +27,24 @@ interface MessagesRawContract /** * @api * - * @param string $messageID Path param: ID of the message to edit + * @param string $messageID message ID + * @param array|MessageRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function retrieve( + string $messageID, + array|MessageRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $messageID path param: Message ID * @param array|MessageUpdateParams $params * @param RequestOpts|null $requestOptions * @@ -42,7 +61,7 @@ public function update( /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array|MessageListParams $params * @param RequestOpts|null $requestOptions * @@ -56,6 +75,23 @@ public function list( RequestOptions|array|null $requestOptions = null, ): BaseResponse; + /** + * @api + * + * @param string $messageID path param: Message ID + * @param array|MessageDeleteParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function delete( + string $messageID, + array|MessageDeleteParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + /** * @api * @@ -74,7 +110,7 @@ public function search( /** * @api * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array|MessageSendParams $params * @param RequestOpts|null $requestOptions * diff --git a/src/Services/AccountsRawService.php b/src/Services/AccountsRawService.php index 64937d1..aa7a338 100644 --- a/src/Services/AccountsRawService.php +++ b/src/Services/AccountsRawService.php @@ -28,7 +28,7 @@ public function __construct(private Client $client) {} /** * @api * - * Lists chat accounts across networks (WhatsApp, Telegram, Twitter/X, etc.) actively connected to this Beeper Desktop instance + * List Chat Accounts connected to this Beeper Desktop instance, including bridge metadata and network identity. * * @param RequestOpts|null $requestOptions * diff --git a/src/Services/AccountsService.php b/src/Services/AccountsService.php index 313ef12..0a3f837 100644 --- a/src/Services/AccountsService.php +++ b/src/Services/AccountsService.php @@ -40,7 +40,7 @@ public function __construct(private Client $client) /** * @api * - * Lists chat accounts across networks (WhatsApp, Telegram, Twitter/X, etc.) actively connected to this Beeper Desktop instance + * List Chat Accounts connected to this Beeper Desktop instance, including bridge metadata and network identity. * * @param RequestOpts|null $requestOptions * diff --git a/src/Services/AssetsRawService.php b/src/Services/AssetsRawService.php index 94db5e4..a9ccc0a 100644 --- a/src/Services/AssetsRawService.php +++ b/src/Services/AssetsRawService.php @@ -34,7 +34,7 @@ public function __construct(private Client $client) {} /** * @api * - * Download a Matrix asset using its mxc:// or localmxc:// URL to the device running Beeper Desktop and return the local file URL. + * Download a Matrix file using its mxc:// or localmxc:// URL to the device running Beeper Desktop and return the local file URL. * * @param array{url: string}|AssetDownloadParams $params * @param RequestOpts|null $requestOptions @@ -97,7 +97,7 @@ public function serve( /** * @api * - * Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending messages with attachments. + * Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment. * * @param array{ * file: string|FileParam, fileName?: string, mimeType?: string @@ -131,7 +131,7 @@ public function upload( /** * @api * - * Upload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending messages with attachments. Alternative to the multipart upload endpoint. + * Upload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment. Alternative to the multipart upload endpoint. * * @param array{ * content: string, fileName?: string, mimeType?: string diff --git a/src/Services/AssetsService.php b/src/Services/AssetsService.php index 95dfa91..0610d62 100644 --- a/src/Services/AssetsService.php +++ b/src/Services/AssetsService.php @@ -37,9 +37,9 @@ public function __construct(private Client $client) /** * @api * - * Download a Matrix asset using its mxc:// or localmxc:// URL to the device running Beeper Desktop and return the local file URL. + * Download a Matrix file using its mxc:// or localmxc:// URL to the device running Beeper Desktop and return the local file URL. * - * @param string $url matrix content URL (mxc:// or localmxc://) for the asset to download + * @param string $url matrix content URL (mxc:// or localmxc://) for the file to download * @param RequestOpts|null $requestOptions * * @throws APIException @@ -61,7 +61,7 @@ public function download( * * Stream a file given an mxc://, localmxc://, or file:// URL. Downloads first if not cached. Supports Range requests for seeking in large files. * - * @param string $url Asset URL to serve. Accepts mxc://, localmxc://, or file:// URLs. + * @param string $url File URL to serve. Accepts mxc://, localmxc://, or file:// URLs. * @param RequestOpts|null $requestOptions * * @throws APIException @@ -81,7 +81,7 @@ public function serve( /** * @api * - * Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending messages with attachments. + * Upload a file to a temporary location using multipart/form-data. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment. * * @param string|FileParam $file the file to upload (max 500 MB) * @param string $fileName Original filename. Defaults to the uploaded file name if omitted @@ -109,7 +109,7 @@ public function upload( /** * @api * - * Upload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending messages with attachments. Alternative to the multipart upload endpoint. + * Upload a file using a JSON body with base64-encoded content. Returns an uploadID that can be referenced when sending a message or materializing a draft attachment. Alternative to the multipart upload endpoint. * * @param string $content Base64-encoded file content (max ~500MB decoded) * @param string $fileName Original filename. Generated if omitted diff --git a/src/Services/BeeperDesktopClientRawService.php b/src/Services/BeeperDesktopClientRawService.php index ee0acfe..58f0394 100644 --- a/src/Services/BeeperDesktopClientRawService.php +++ b/src/Services/BeeperDesktopClientRawService.php @@ -15,7 +15,7 @@ use BeeperDesktop\ServiceContracts\BeeperDesktopClientRawContract; /** - * Control the Beeper Desktop application. + * Top-level actions: focus the app window, jump to a chat, or run unified search across chats and messages. * * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ @@ -30,7 +30,7 @@ public function __construct(private Client $client) {} /** * @api * - * Focus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill draft text and attachment. + * Focus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill plain text and an image path. * * @param array{ * chatID?: string, diff --git a/src/Services/BeeperDesktopClientService.php b/src/Services/BeeperDesktopClientService.php index 0d44a9a..8923440 100644 --- a/src/Services/BeeperDesktopClientService.php +++ b/src/Services/BeeperDesktopClientService.php @@ -13,7 +13,7 @@ use BeeperDesktop\ServiceContracts\BeeperDesktopClientContract; /** - * Control the Beeper Desktop application. + * Top-level actions: focus the app window, jump to a chat, or run unified search across chats and messages. * * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ @@ -35,11 +35,11 @@ public function __construct(private Client $client) /** * @api * - * Focus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill draft text and attachment. + * Focus Beeper Desktop and optionally navigate to a specific chat, message, or pre-fill plain text and an image path. * * @param string $chatID Optional Beeper chat ID (or local chat ID) to focus after opening the app. If omitted, only opens/focuses the app. - * @param string $draftAttachmentPath optional draft attachment path to populate in the message input field - * @param string $draftText optional draft text to populate in the message input field + * @param string $draftAttachmentPath optional image path to populate in the message input field + * @param string $draftText optional plain text to populate in the message input field * @param string $messageID Optional message ID. Jumps to that message in the chat when opening. * @param RequestOpts|null $requestOptions * diff --git a/src/Services/Chats/Messages/ReactionsRawService.php b/src/Services/Chats/Messages/ReactionsRawService.php index dcfb515..43fcf90 100644 --- a/src/Services/Chats/Messages/ReactionsRawService.php +++ b/src/Services/Chats/Messages/ReactionsRawService.php @@ -32,8 +32,8 @@ public function __construct(private Client $client) {} * * Remove the reaction added by the authenticated user from an existing message. * - * @param string $messageID Path param: ID of the message to remove a reaction from - * @param array{chatID: string, reactionKey: string}|ReactionDeleteParams $params + * @param string $reactionKey Reaction key to remove (emoji, shortcode, or custom emoji key) + * @param array{chatID: string, messageID: string}|ReactionDeleteParams $params * @param RequestOpts|null $requestOptions * * @return BaseResponse @@ -41,7 +41,7 @@ public function __construct(private Client $client) {} * @throws APIException */ public function delete( - string $messageID, + string $reactionKey, array|ReactionDeleteParams $params, RequestOptions|array|null $requestOptions = null, ): BaseResponse { @@ -51,12 +51,18 @@ public function delete( ); $chatID = $parsed['chatID']; unset($parsed['chatID']); + $messageID = $parsed['messageID']; + unset($parsed['messageID']); // @phpstan-ignore-next-line return.type return $this->client->request( method: 'delete', - path: ['v1/chats/%1$s/messages/%2$s/reactions', $chatID, $messageID], - query: $parsed, + path: [ + 'v1/chats/%1$s/messages/%2$s/reactions/%3$s', + $chatID, + $messageID, + $reactionKey, + ], options: $options, convert: ReactionDeleteResponse::class, ); @@ -67,7 +73,7 @@ public function delete( * * Add a reaction to an existing message. * - * @param string $messageID Path param: ID of the message to add a reaction to + * @param string $messageID path param: Message ID * @param array{ * chatID: string, reactionKey: string, transactionID?: string * }|ReactionAddParams $params diff --git a/src/Services/Chats/Messages/ReactionsService.php b/src/Services/Chats/Messages/ReactionsService.php index 06fd937..7c8daa2 100644 --- a/src/Services/Chats/Messages/ReactionsService.php +++ b/src/Services/Chats/Messages/ReactionsService.php @@ -37,25 +37,25 @@ public function __construct(private Client $client) * * Remove the reaction added by the authenticated user from an existing message. * - * @param string $messageID Path param: ID of the message to remove a reaction from - * @param string $chatID path param: Unique identifier of the chat - * @param string $reactionKey Query param: Reaction key to remove + * @param string $reactionKey Reaction key to remove (emoji, shortcode, or custom emoji key) + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param string $messageID message ID * @param RequestOpts|null $requestOptions * * @throws APIException */ public function delete( - string $messageID, - string $chatID, string $reactionKey, + string $chatID, + string $messageID, RequestOptions|array|null $requestOptions = null, ): ReactionDeleteResponse { $params = Util::removeNulls( - ['chatID' => $chatID, 'reactionKey' => $reactionKey] + ['chatID' => $chatID, 'messageID' => $messageID] ); // @phpstan-ignore-next-line argument.type - $response = $this->raw->delete($messageID, params: $params, requestOptions: $requestOptions); + $response = $this->raw->delete($reactionKey, params: $params, requestOptions: $requestOptions); return $response->parse(); } @@ -65,10 +65,10 @@ public function delete( * * Add a reaction to an existing message. * - * @param string $messageID Path param: ID of the message to add a reaction to - * @param string $chatID path param: Unique identifier of the chat + * @param string $messageID path param: Message ID + * @param string $chatID Path param: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param string $reactionKey Body param: Reaction key to add (emoji, shortcode, or custom emoji key) - * @param string $transactionID Body param: Optional transaction ID for deduplication and local echo tracking + * @param string $transactionID Body param: Optional transaction ID for deduplication and send tracking * @param RequestOpts|null $requestOptions * * @throws APIException diff --git a/src/Services/Chats/RemindersRawService.php b/src/Services/Chats/RemindersRawService.php index 319b3a8..2ad04e2 100644 --- a/src/Services/Chats/RemindersRawService.php +++ b/src/Services/Chats/RemindersRawService.php @@ -31,7 +31,7 @@ public function __construct(private Client $client) {} * * Set a reminder for a chat at a specific time * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array{reminder: Reminder|ReminderShape}|ReminderCreateParams $params * @param RequestOpts|null $requestOptions * @@ -64,7 +64,7 @@ public function create( * * Clear an existing reminder from a chat * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param RequestOpts|null $requestOptions * * @return BaseResponse diff --git a/src/Services/Chats/RemindersService.php b/src/Services/Chats/RemindersService.php index 8237a7e..dad2e0f 100644 --- a/src/Services/Chats/RemindersService.php +++ b/src/Services/Chats/RemindersService.php @@ -37,7 +37,7 @@ public function __construct(private Client $client) * * Set a reminder for a chat at a specific time * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param Reminder|ReminderShape $reminder Reminder configuration * @param RequestOpts|null $requestOptions * @@ -61,7 +61,7 @@ public function create( * * Clear an existing reminder from a chat * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param RequestOpts|null $requestOptions * * @throws APIException diff --git a/src/Services/ChatsRawService.php b/src/Services/ChatsRawService.php index c06ceee..4ad18ed 100644 --- a/src/Services/ChatsRawService.php +++ b/src/Services/ChatsRawService.php @@ -11,6 +11,8 @@ use BeeperDesktop\Chats\ChatListParams; use BeeperDesktop\Chats\ChatListParams\Direction; use BeeperDesktop\Chats\ChatListResponse; +use BeeperDesktop\Chats\ChatMarkReadParams; +use BeeperDesktop\Chats\ChatMarkUnreadParams; use BeeperDesktop\Chats\ChatNewResponse; use BeeperDesktop\Chats\ChatRetrieveParams; use BeeperDesktop\Chats\ChatSearchParams; @@ -19,6 +21,8 @@ use BeeperDesktop\Chats\ChatStartParams; use BeeperDesktop\Chats\ChatStartParams\User; use BeeperDesktop\Chats\ChatStartResponse; +use BeeperDesktop\Chats\ChatUpdateParams; +use BeeperDesktop\Chats\ChatUpdateParams\Draft; use BeeperDesktop\Client; use BeeperDesktop\Core\Contracts\BaseResponse; use BeeperDesktop\Core\Exceptions\APIException; @@ -30,6 +34,7 @@ /** * Manage chats. * + * @phpstan-import-type DraftShape from \BeeperDesktop\Chats\ChatUpdateParams\Draft * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatStartParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ @@ -44,7 +49,7 @@ public function __construct(private Client $client) {} /** * @api * - * Create a direct or group chat from participant IDs. + * Create a direct or group chat from participant IDs. Returns the created chat. * * @param array{ * accountID: string, @@ -83,7 +88,7 @@ public function create( * * Retrieve chat details including metadata, participants, and latest message * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array{maxParticipantCount?: int|null}|ChatRetrieveParams $params * @param RequestOpts|null $requestOptions * @@ -111,6 +116,49 @@ public function retrieve( ); } + /** + * @api + * + * Update supported chat fields. Non-empty draft objects are accepted only when the current draft is empty. Send draft=null to clear the draft before setting new draft text or attachments. + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param array{ + * description?: string|null, + * draft?: Draft|DraftShape|null, + * imgURL?: string|null, + * isArchived?: bool, + * isLowPriority?: bool, + * isMuted?: bool, + * isPinned?: bool, + * messageExpirySeconds?: int|null, + * title?: string|null, + * }|ChatUpdateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function update( + string $chatID, + array|ChatUpdateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = ChatUpdateParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'patch', + path: ['v1/chats/%1$s', $chatID], + body: (object) $parsed, + options: $options, + convert: Chat::class, + ); + } + /** * @api * @@ -152,7 +200,7 @@ public function list( * * Archive or unarchive a chat. Set archived=true to move to archive, archived=false to move back to inbox * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array{archived?: bool}|ChatArchiveParams $params * @param RequestOpts|null $requestOptions * @@ -180,6 +228,97 @@ public function archive( ); } + /** + * @api + * + * Mark a chat as read, optionally through a specific message ID. + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param array{messageID?: string}|ChatMarkReadParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function markRead( + string $chatID, + array|ChatMarkReadParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = ChatMarkReadParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/chats/%1$s/read', $chatID], + body: (object) $parsed, + options: $options, + convert: Chat::class, + ); + } + + /** + * @api + * + * Mark a chat as unread, optionally from a specific message ID. + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param array{messageID?: string}|ChatMarkUnreadParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function markUnread( + string $chatID, + array|ChatMarkUnreadParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = ChatMarkUnreadParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/chats/%1$s/unread', $chatID], + body: (object) $parsed, + options: $options, + convert: Chat::class, + ); + } + + /** + * @api + * + * Force a delivery notification when supported by the underlying network. Currently intended for iMessage on macOS; unsupported networks return an error. + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function notifyAnyway( + string $chatID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/chats/%1$s/notify-anyway', $chatID], + options: $requestOptions, + convert: Chat::class, + ); + } + /** * @api * @@ -228,7 +367,7 @@ public function search( /** * @api * - * Resolve a user/contact and open a direct chat. Reuses an existing direct chat when one is found. Available in Beeper Desktop v4.2.799+. + * Resolve a user/contact and open a direct chat. Reuses and returns an existing direct chat when one is found. Available in Beeper Desktop v4.2.808+. * * @param array{ * accountID: string, @@ -254,7 +393,7 @@ public function start( // @phpstan-ignore-next-line return.type return $this->client->request( method: 'post', - path: 'v1/chats.start', + path: 'v1/chats/start', body: (object) $parsed, options: $options, convert: ChatStartResponse::class, diff --git a/src/Services/ChatsService.php b/src/Services/ChatsService.php index 51fdd92..6651871 100644 --- a/src/Services/ChatsService.php +++ b/src/Services/ChatsService.php @@ -13,6 +13,7 @@ use BeeperDesktop\Chats\ChatSearchParams\Scope; use BeeperDesktop\Chats\ChatStartParams\User; use BeeperDesktop\Chats\ChatStartResponse; +use BeeperDesktop\Chats\ChatUpdateParams\Draft; use BeeperDesktop\Client; use BeeperDesktop\Core\Exceptions\APIException; use BeeperDesktop\Core\Util; @@ -26,6 +27,7 @@ /** * Manage chats. * + * @phpstan-import-type DraftShape from \BeeperDesktop\Chats\ChatUpdateParams\Draft * @phpstan-import-type UserShape from \BeeperDesktop\Chats\ChatStartParams\User * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ @@ -59,7 +61,7 @@ public function __construct(private Client $client) /** * @api * - * Create a direct or group chat from participant IDs. + * Create a direct or group chat from participant IDs. Returns the created chat. * * @param string $accountID account to create or start the chat on * @param list $participantIDs user IDs to include in the new chat @@ -99,15 +101,15 @@ public function create( * * Retrieve chat details including metadata, participants, and latest message * - * @param string $chatID unique identifier of the chat - * @param int|null $maxParticipantCount Maximum number of participants to return. Use -1 for all; otherwise 0–500. Defaults to all (-1). + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param int|null $maxParticipantCount Maximum number of participants to return. Use -1 for all; otherwise 0-500. Defaults to 100. List and search endpoints return up to 20 participants per chat. * @param RequestOpts|null $requestOptions * * @throws APIException */ public function retrieve( string $chatID, - ?int $maxParticipantCount = -1, + ?int $maxParticipantCount = 100, RequestOptions|array|null $requestOptions = null, ): Chat { $params = Util::removeNulls( @@ -120,6 +122,58 @@ public function retrieve( return $response->parse(); } + /** + * @api + * + * Update supported chat fields. Non-empty draft objects are accepted only when the current draft is empty. Send draft=null to clear the draft before setting new draft text or attachments. + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param string|null $description Group chat description/topic. Support depends on the chat account and chat permissions. + * @param Draft|DraftShape|null $draft Draft object to set or clear. Non-empty drafts are only accepted when the current draft is empty. Send draft=null to clear text and attachments together before setting a new draft. + * @param string|null $imgURL Local filesystem path to a group chat avatar image. Support depends on the chat account and chat permissions. + * @param bool $isArchived archive or unarchive the chat + * @param bool $isLowPriority mark or unmark the chat as low priority when supported by the account + * @param bool $isMuted mute or unmute the chat + * @param bool $isPinned pin or unpin the chat when supported by the account + * @param int|null $messageExpirySeconds disappearing-message timer in seconds, or null to clear when supported + * @param string|null $title Custom chat title. Support depends on the chat account and chat permissions. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function update( + string $chatID, + ?string $description = null, + Draft|array|null $draft = null, + ?string $imgURL = null, + ?bool $isArchived = null, + ?bool $isLowPriority = null, + ?bool $isMuted = null, + ?bool $isPinned = null, + ?int $messageExpirySeconds = null, + ?string $title = null, + RequestOptions|array|null $requestOptions = null, + ): Chat { + $params = Util::removeNulls( + [ + 'description' => $description, + 'draft' => $draft, + 'imgURL' => $imgURL, + 'isArchived' => $isArchived, + 'isLowPriority' => $isLowPriority, + 'isMuted' => $isMuted, + 'isPinned' => $isPinned, + 'messageExpirySeconds' => $messageExpirySeconds, + 'title' => $title, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->update($chatID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + /** * @api * @@ -159,7 +213,7 @@ public function list( * * Archive or unarchive a chat. Set archived=true to move to archive, archived=false to move back to inbox * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param bool $archived True to archive, false to unarchive * @param RequestOpts|null $requestOptions * @@ -178,6 +232,74 @@ public function archive( return $response->parse(); } + /** + * @api + * + * Mark a chat as read, optionally through a specific message ID. + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param string $messageID optional message ID to mark read through + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function markRead( + string $chatID, + ?string $messageID = null, + RequestOptions|array|null $requestOptions = null, + ): Chat { + $params = Util::removeNulls(['messageID' => $messageID]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->markRead($chatID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Mark a chat as unread, optionally from a specific message ID. + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param string $messageID optional message ID to mark unread from + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function markUnread( + string $chatID, + ?string $messageID = null, + RequestOptions|array|null $requestOptions = null, + ): Chat { + $params = Util::removeNulls(['messageID' => $messageID]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->markUnread($chatID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Force a delivery notification when supported by the underlying network. Currently intended for iMessage on macOS; unsupported networks return an error. + * + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function notifyAnyway( + string $chatID, + RequestOptions|array|null $requestOptions = null + ): Chat { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->notifyAnyway($chatID, requestOptions: $requestOptions); + + return $response->parse(); + } + /** * @api * @@ -242,7 +364,7 @@ public function search( /** * @api * - * Resolve a user/contact and open a direct chat. Reuses an existing direct chat when one is found. Available in Beeper Desktop v4.2.799+. + * Resolve a user/contact and open a direct chat. Reuses and returns an existing direct chat when one is found. Available in Beeper Desktop v4.2.808+. * * @param string $accountID account to create or start the chat on * @param User|UserShape $user merged user-like contact payload used to resolve the best identifier diff --git a/src/Services/InfoRawService.php b/src/Services/InfoRawService.php index c5a4228..4b3fba5 100644 --- a/src/Services/InfoRawService.php +++ b/src/Services/InfoRawService.php @@ -12,7 +12,7 @@ use BeeperDesktop\ServiceContracts\InfoRawContract; /** - * Control the Beeper Desktop application. + * Server discovery and capability metadata. Use /v1/info before authentication setup. * * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ @@ -27,7 +27,7 @@ public function __construct(private Client $client) {} /** * @api * - * Returns app, platform, server, and endpoint discovery metadata for this Beeper Desktop instance. + * Returns app, platform, server, endpoint discovery, OAuth, and WebSocket metadata for this Beeper Desktop instance. * * @param RequestOpts|null $requestOptions * diff --git a/src/Services/InfoService.php b/src/Services/InfoService.php index 20ccaf2..adb1818 100644 --- a/src/Services/InfoService.php +++ b/src/Services/InfoService.php @@ -11,7 +11,7 @@ use BeeperDesktop\ServiceContracts\InfoContract; /** - * Control the Beeper Desktop application. + * Server discovery and capability metadata. Use /v1/info before authentication setup. * * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions */ @@ -33,7 +33,7 @@ public function __construct(private Client $client) /** * @api * - * Returns app, platform, server, and endpoint discovery metadata for this Beeper Desktop instance. + * Returns app, platform, server, endpoint discovery, OAuth, and WebSocket metadata for this Beeper Desktop instance. * * @param RequestOpts|null $requestOptions * diff --git a/src/Services/MessagesRawService.php b/src/Services/MessagesRawService.php index 0da852e..500e46f 100644 --- a/src/Services/MessagesRawService.php +++ b/src/Services/MessagesRawService.php @@ -10,8 +10,10 @@ use BeeperDesktop\CursorNoLimit; use BeeperDesktop\CursorSearch; use BeeperDesktop\Message; +use BeeperDesktop\Messages\MessageDeleteParams; use BeeperDesktop\Messages\MessageListParams; use BeeperDesktop\Messages\MessageListParams\Direction; +use BeeperDesktop\Messages\MessageRetrieveParams; use BeeperDesktop\Messages\MessageSearchParams; use BeeperDesktop\Messages\MessageSearchParams\ChatType; use BeeperDesktop\Messages\MessageSearchParams\MediaType; @@ -37,12 +39,46 @@ final class MessagesRawService implements MessagesRawContract */ public function __construct(private Client $client) {} + /** + * @api + * + * Retrieve a message by final message ID, pendingMessageID, or Matrix event ID. Chat ID may be a Beeper chat ID or local chat ID. + * + * @param string $messageID message ID + * @param array{chatID: string}|MessageRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function retrieve( + string $messageID, + array|MessageRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = MessageRetrieveParams::parseRequest( + $params, + $requestOptions, + ); + $chatID = $parsed['chatID']; + unset($parsed['chatID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: ['v1/chats/%1$s/messages/%2$s', $chatID, $messageID], + options: $options, + convert: Message::class, + ); + } + /** * @api * * Edit the text content of an existing message. Messages with attachments cannot be edited. * - * @param string $messageID Path param: ID of the message to edit + * @param string $messageID path param: Message ID * @param array{chatID: string, text: string}|MessageUpdateParams $params * @param RequestOpts|null $requestOptions * @@ -77,7 +113,7 @@ public function update( * * List all messages in a chat with cursor-based pagination. Sorted by timestamp. * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array{ * cursor?: string, direction?: Direction|value-of * }|MessageListParams $params @@ -108,6 +144,43 @@ public function list( ); } + /** + * @api + * + * Delete a message by final message ID. Pending message IDs are not accepted because messages cannot be deleted while sending. + * + * @param string $messageID path param: Message ID + * @param array{ + * chatID: string, forEveryone?: bool|null + * }|MessageDeleteParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse + * + * @throws APIException + */ + public function delete( + string $messageID, + array|MessageDeleteParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = MessageDeleteParams::parseRequest( + $params, + $requestOptions, + ); + $chatID = $parsed['chatID']; + unset($parsed['chatID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'delete', + path: ['v1/chats/%1$s/messages/%2$s', $chatID, $messageID], + query: $parsed, + options: $options, + convert: null, + ); + } + /** * @api * @@ -159,7 +232,7 @@ public function search( * * Send a text message to a specific chat. Supports replying to existing messages. Returns a pending message ID. * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param array{ * attachment?: Attachment|AttachmentShape, * replyToMessageID?: string, diff --git a/src/Services/MessagesService.php b/src/Services/MessagesService.php index 2045b00..dbb0afd 100644 --- a/src/Services/MessagesService.php +++ b/src/Services/MessagesService.php @@ -40,13 +40,37 @@ public function __construct(private Client $client) $this->raw = new MessagesRawService($client); } + /** + * @api + * + * Retrieve a message by final message ID, pendingMessageID, or Matrix event ID. Chat ID may be a Beeper chat ID or local chat ID. + * + * @param string $messageID message ID + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieve( + string $messageID, + string $chatID, + RequestOptions|array|null $requestOptions = null, + ): Message { + $params = Util::removeNulls(['chatID' => $chatID]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->retrieve($messageID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + /** * @api * * Edit the text content of an existing message. Messages with attachments cannot be edited. * - * @param string $messageID Path param: ID of the message to edit - * @param string $chatID path param: Unique identifier of the chat + * @param string $messageID path param: Message ID + * @param string $chatID Path param: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param string $text Body param: New text content for the message * @param RequestOpts|null $requestOptions * @@ -71,7 +95,7 @@ public function update( * * List all messages in a chat with cursor-based pagination. Sorted by timestamp. * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param string $cursor Opaque pagination cursor; do not inspect. Use together with 'direction'. * @param Direction|value-of $direction Pagination direction used with 'cursor': 'before' fetches older results, 'after' fetches newer results. Defaults to 'before' when only 'cursor' is provided. * @param RequestOpts|null $requestOptions @@ -96,6 +120,34 @@ public function list( return $response->parse(); } + /** + * @api + * + * Delete a message by final message ID. Pending message IDs are not accepted because messages cannot be deleted while sending. + * + * @param string $messageID path param: Message ID + * @param string $chatID Path param: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. + * @param bool|null $forEveryone query param: True to request deletion for everyone when the network supports it; false to delete only for the authenticated user when supported + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function delete( + string $messageID, + string $chatID, + ?bool $forEveryone = true, + RequestOptions|array|null $requestOptions = null, + ): mixed { + $params = Util::removeNulls( + ['chatID' => $chatID, 'forEveryone' => $forEveryone] + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->delete($messageID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + /** * @api * @@ -165,10 +217,10 @@ public function search( * * Send a text message to a specific chat. Supports replying to existing messages. Returns a pending message ID. * - * @param string $chatID unique identifier of the chat + * @param string $chatID Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available. * @param Attachment|AttachmentShape $attachment Single attachment to send with the message * @param string $replyToMessageID Provide a message ID to send this as a reply to an existing message - * @param string $text Text content of the message you want to send. You may use markdown. + * @param string $text Draft text. Plain text and Markdown are converted to Matrix HTML with the same rules used by send and edit. * @param RequestOpts|null $requestOptions * * @throws APIException diff --git a/src/User.php b/src/User.php index d45604c..9787d40 100644 --- a/src/User.php +++ b/src/User.php @@ -53,7 +53,7 @@ final class User implements BaseModel public ?string $fullName; /** - * Avatar image URL if available. May be temporary or local-only to this device; download promptly if durable access is needed. + * Avatar image URL if available. This may be a remote URL, Matrix media URL, data URL, or local filesystem URL depending on source and endpoint. May be temporary or local-only to this device; download promptly if durable access is needed. */ #[Optional] public ?string $imgURL; @@ -170,7 +170,7 @@ public function withFullName(string $fullName): self } /** - * Avatar image URL if available. May be temporary or local-only to this device; download promptly if durable access is needed. + * Avatar image URL if available. This may be a remote URL, Matrix media URL, data URL, or local filesystem URL depending on source and endpoint. May be temporary or local-only to this device; download promptly if durable access is needed. */ public function withImgURL(string $imgURL): self { diff --git a/tests/Services/AssetsTest.php b/tests/Services/AssetsTest.php index 66e0c1f..6aaeb61 100644 --- a/tests/Services/AssetsTest.php +++ b/tests/Services/AssetsTest.php @@ -11,7 +11,6 @@ use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use Tests\UnsupportedMockTests; /** * @internal @@ -56,10 +55,6 @@ public function testDownloadWithOptionalParams(): void #[Test] public function testServe(): void { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Generated PHP mock test parses the binary stream response as null despite the OpenAPI response being application/octet-stream format=binary.'); - } - $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType @@ -69,10 +64,6 @@ public function testServe(): void #[Test] public function testServeWithOptionalParams(): void { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Generated PHP mock test parses the binary stream response as null despite the OpenAPI response being application/octet-stream format=binary.'); - } - $result = $this->client->assets->serve(url: 'x'); // @phpstan-ignore-next-line method.alreadyNarrowedType diff --git a/tests/Services/Chats/Messages/ReactionsTest.php b/tests/Services/Chats/Messages/ReactionsTest.php index de3125a..08f4115 100644 --- a/tests/Services/Chats/Messages/ReactionsTest.php +++ b/tests/Services/Chats/Messages/ReactionsTest.php @@ -32,9 +32,9 @@ protected function setUp(): void public function testDelete(): void { $result = $this->client->chats->messages->reactions->delete( - 'messageID', + 'x', chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', - reactionKey: 'x' + messageID: '1343993' ); // @phpstan-ignore-next-line method.alreadyNarrowedType @@ -45,9 +45,9 @@ public function testDelete(): void public function testDeleteWithOptionalParams(): void { $result = $this->client->chats->messages->reactions->delete( - 'messageID', + 'x', chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', - reactionKey: 'x' + messageID: '1343993' ); // @phpstan-ignore-next-line method.alreadyNarrowedType @@ -58,7 +58,7 @@ public function testDeleteWithOptionalParams(): void public function testAdd(): void { $result = $this->client->chats->messages->reactions->add( - 'messageID', + '1343993', chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', reactionKey: 'x' ); @@ -71,7 +71,7 @@ public function testAdd(): void public function testAddWithOptionalParams(): void { $result = $this->client->chats->messages->reactions->add( - 'messageID', + '1343993', chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', reactionKey: 'x', transactionID: 'transactionID', diff --git a/tests/Services/Chats/RemindersTest.php b/tests/Services/Chats/RemindersTest.php index e489678..12e0ca9 100644 --- a/tests/Services/Chats/RemindersTest.php +++ b/tests/Services/Chats/RemindersTest.php @@ -31,7 +31,9 @@ public function testCreate(): void { $result = $this->client->chats->reminders->create( '!NCdzlIaMjZUmvmvyHU:beeper.com', - reminder: ['remindAtMs' => 0] + reminder: [ + 'remindAt' => new \DateTimeImmutable('2025-08-31T23:30:12.520Z'), + ], ); // @phpstan-ignore-next-line method.alreadyNarrowedType @@ -43,7 +45,10 @@ public function testCreateWithOptionalParams(): void { $result = $this->client->chats->reminders->create( '!NCdzlIaMjZUmvmvyHU:beeper.com', - reminder: ['remindAtMs' => 0, 'dismissOnIncomingMessage' => true], + reminder: [ + 'remindAt' => new \DateTimeImmutable('2025-08-31T23:30:12.520Z'), + 'dismissOnIncomingMessage' => true, + ], ); // @phpstan-ignore-next-line method.alreadyNarrowedType diff --git a/tests/Services/ChatsTest.php b/tests/Services/ChatsTest.php index 3b7fbfa..57b0f7d 100644 --- a/tests/Services/ChatsTest.php +++ b/tests/Services/ChatsTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; -use Tests\UnsupportedMockTests; /** * @internal @@ -70,6 +69,15 @@ public function testRetrieve(): void $this->assertInstanceOf(Chat::class, $result); } + #[Test] + public function testUpdate(): void + { + $result = $this->client->chats->update('!NCdzlIaMjZUmvmvyHU:beeper.com'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(Chat::class, $result); + } + #[Test] public function testList(): void { @@ -93,6 +101,37 @@ public function testArchive(): void $this->assertNull($result); } + #[Test] + public function testMarkRead(): void + { + $result = $this->client->chats->markRead('!NCdzlIaMjZUmvmvyHU:beeper.com'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(Chat::class, $result); + } + + #[Test] + public function testMarkUnread(): void + { + $result = $this->client->chats->markUnread( + '!NCdzlIaMjZUmvmvyHU:beeper.com' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(Chat::class, $result); + } + + #[Test] + public function testNotifyAnyway(): void + { + $result = $this->client->chats->notifyAnyway( + '!NCdzlIaMjZUmvmvyHU:beeper.com' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(Chat::class, $result); + } + #[Test] public function testSearch(): void { @@ -110,10 +149,6 @@ public function testSearch(): void #[Test] public function testStart(): void { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Stainless mock tests currently load the project-published OpenAPI spec URL, which may not include newly-added local-only endpoints during build checks.'); - } - $result = $this->client->chats->start(accountID: 'accountID', user: []); // @phpstan-ignore-next-line method.alreadyNarrowedType @@ -123,10 +158,6 @@ public function testStart(): void #[Test] public function testStartWithOptionalParams(): void { - if (UnsupportedMockTests::$skip) { - $this->markTestSkipped('Stainless mock tests currently load the project-published OpenAPI spec URL, which may not include newly-added local-only endpoints during build checks.'); - } - $result = $this->client->chats->start( accountID: 'accountID', user: [ diff --git a/tests/Services/MessagesTest.php b/tests/Services/MessagesTest.php index f0691c6..67ee229 100644 --- a/tests/Services/MessagesTest.php +++ b/tests/Services/MessagesTest.php @@ -31,11 +31,35 @@ protected function setUp(): void $this->client = $client; } + #[Test] + public function testRetrieve(): void + { + $result = $this->client->messages->retrieve( + '1343993', + chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(Message::class, $result); + } + + #[Test] + public function testRetrieveWithOptionalParams(): void + { + $result = $this->client->messages->retrieve( + '1343993', + chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(Message::class, $result); + } + #[Test] public function testUpdate(): void { $result = $this->client->messages->update( - 'messageID', + '1343993', chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', text: 'x' ); @@ -48,7 +72,7 @@ public function testUpdate(): void public function testUpdateWithOptionalParams(): void { $result = $this->client->messages->update( - 'messageID', + '1343993', chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', text: 'x' ); @@ -71,6 +95,31 @@ public function testList(): void } } + #[Test] + public function testDelete(): void + { + $result = $this->client->messages->delete( + '1343993', + chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNull($result); + } + + #[Test] + public function testDeleteWithOptionalParams(): void + { + $result = $this->client->messages->delete( + '1343993', + chatID: '!NCdzlIaMjZUmvmvyHU:beeper.com', + forEveryone: true + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNull($result); + } + #[Test] public function testSearch(): void { From 3a41088103be62e91f609605f2b5e994921a68dc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 03:09:22 +0000 Subject: [PATCH 41/48] fix: guzzle requires special handling to enable streaming --- composer.json | 1 + composer.lock | 374 +++++++++++++++++- src/Client.php | 6 + src/Core/BaseClient.php | 6 +- src/Core/FileParam.php | 2 +- .../Implementation/StreamingHttpClient.php | 29 ++ src/Core/Util.php | 12 + src/RequestOptions.php | 17 + tests/Core/StreamingTransportTest.php | 122 ++++++ 9 files changed, 565 insertions(+), 4 deletions(-) create mode 100644 src/Core/Implementation/StreamingHttpClient.php create mode 100644 tests/Core/StreamingTransportTest.php diff --git a/composer.json b/composer.json index 93480e2..c429851 100644 --- a/composer.json +++ b/composer.json @@ -38,6 +38,7 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^3", + "guzzlehttp/guzzle": "^7", "nyholm/psr7": "^1", "pestphp/pest": "^3", "php-http/mock-client": "^1", diff --git a/composer.lock b/composer.lock index 7a5e63d..b0e2283 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ffa287ea8babf60e021f37e62c6c207a", + "content-hash": "bbae64cb4d21c987158bc3723eda4226", "packages": [ { "name": "php-http/discovery", @@ -968,6 +968,332 @@ ], "time": "2026-01-08T21:57:37+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "7.10.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-08-23T22:36:01+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "481557b130ef3790cf82b713667b43030dc9c957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2025-08-22T14:34:08+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884", + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "jshttp/mime-db": "1.54.0.1", + "phpunit/phpunit": "^8.5.44 || ^9.6.25" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.9.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2026-03-10T16:41:02+00:00" + }, { "name": "jean85/pretty-package-versions", "version": "2.1.1", @@ -3250,6 +3576,50 @@ }, "time": "2021-10-29T13:26:27+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "react/cache", "version": "v1.2.0", @@ -6680,5 +7050,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.6.0" } diff --git a/src/Client.php b/src/Client.php index 9806990..eadd4d1 100644 --- a/src/Client.php +++ b/src/Client.php @@ -8,6 +8,7 @@ use BeeperDesktop\BeeperDesktopClientService\BeeperDesktopClientServiceSearchResponse; use BeeperDesktop\Core\BaseClient; use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Implementation\StreamingHttpClient; use BeeperDesktop\Core\Util; use BeeperDesktop\Services\AccountsService; use BeeperDesktop\Services\AssetsService; @@ -86,6 +87,11 @@ public function __construct( $requestOptions, ); + if (is_null($options->streamingTransporter)) { + assert(!is_null($options->transporter)); + $options->streamingTransporter = new StreamingHttpClient($options->transporter); + } + /** @var array $headers */ $headers = [ 'Content-Type' => 'application/json', diff --git a/src/Core/BaseClient.php b/src/Core/BaseClient.php index bed6a0d..0e2c3dd 100644 --- a/src/Core/BaseClient.php +++ b/src/Core/BaseClient.php @@ -246,11 +246,15 @@ protected function sendRequest( $req = $req->withHeader('X-Stainless-Retry-Count', strval($retryCount)); $req = Util::withSetBody($opts->streamFactory, req: $req, body: $data); + $transporter = Util::isStreamingRequest($req) + ? ($opts->streamingTransporter ?? $opts->transporter) + : $opts->transporter; + $rsp = null; $err = null; try { - $rsp = $opts->transporter->sendRequest($req); + $rsp = $transporter->sendRequest($req); } catch (ClientExceptionInterface $e) { $err = $e; } diff --git a/src/Core/FileParam.php b/src/Core/FileParam.php index eb8db4a..7614a33 100644 --- a/src/Core/FileParam.php +++ b/src/Core/FileParam.php @@ -41,7 +41,7 @@ public static function fromResource(mixed $resource, ?string $filename = null, s throw new \InvalidArgumentException('Expected a resource, got '.get_debug_type($resource)); } - if (null === $filename) { + if (is_null($filename)) { $meta = stream_get_meta_data($resource); $filename = basename($meta['uri'] ?? 'upload'); } diff --git a/src/Core/Implementation/StreamingHttpClient.php b/src/Core/Implementation/StreamingHttpClient.php new file mode 100644 index 0000000..8e860a9 --- /dev/null +++ b/src/Core/Implementation/StreamingHttpClient.php @@ -0,0 +1,29 @@ +inner, '\GuzzleHttp\Client')) { + return $this->inner->send($request, ['stream' => true]); + } + + return $this->inner->sendRequest($request); + } +} diff --git a/src/Core/Util.php b/src/Core/Util.php index b385aff..85ddc59 100644 --- a/src/Core/Util.php +++ b/src/Core/Util.php @@ -25,6 +25,8 @@ final class Util public const JSONL_CONTENT_TYPE = '/^application\/(:?x-(?:n|l)djson)|(:?(?:x-)?jsonl)/'; + public const STREAMING_CONTENT_TYPE = ['/^text\/event-stream/', self::JSONL_CONTENT_TYPE]; + public static function getenv(string $key): ?string { if (array_key_exists($key, array: $_ENV)) { @@ -217,6 +219,16 @@ public static function joinUri( return $base->withQuery($qs); } + public static function isStreamingRequest(RequestInterface $request): bool + { + $accept = $request->getHeaderLine('Accept'); + + return !empty(array_filter( + self::STREAMING_CONTENT_TYPE, + static fn (string $pattern) => (bool) preg_match($pattern, subject: $accept), + )); + } + /** * @param array|null> $headers */ diff --git a/src/RequestOptions.php b/src/RequestOptions.php index 58bc8dd..03fcb72 100644 --- a/src/RequestOptions.php +++ b/src/RequestOptions.php @@ -23,6 +23,7 @@ * extraQueryParams?: array|null, * extraBodyParams?: mixed, * transporter?: ClientInterface|null, + * streamingTransporter?: ClientInterface|null, * uriFactory?: UriFactoryInterface|null, * streamFactory?: StreamFactoryInterface|null, * requestFactory?: RequestFactoryInterface|null, @@ -60,6 +61,9 @@ final class RequestOptions implements BaseModel #[Optional] public ?ClientInterface $transporter; + #[Optional] + public ?ClientInterface $streamingTransporter; + #[Optional] public ?UriFactoryInterface $uriFactory; @@ -98,6 +102,7 @@ public static function with( ?array $extraQueryParams = null, mixed $extraBodyParams = null, ?ClientInterface $transporter = null, + ?ClientInterface $streamingTransporter = null, ?UriFactoryInterface $uriFactory = null, ?StreamFactoryInterface $streamFactory = null, ?RequestFactoryInterface $requestFactory = null, @@ -114,6 +119,9 @@ public static function with( null !== $extraQueryParams && $self->extraQueryParams = $extraQueryParams; null !== $extraBodyParams && $self->extraBodyParams = $extraBodyParams; null !== $transporter && $self->transporter = $transporter; + null !== $streamingTransporter && $self + ->streamingTransporter = $streamingTransporter + ; null !== $uriFactory && $self->uriFactory = $uriFactory; null !== $streamFactory && $self->streamFactory = $streamFactory; null !== $requestFactory && $self->requestFactory = $requestFactory; @@ -191,6 +199,15 @@ public function withTransporter(ClientInterface $transporter): self return $self; } + public function withStreamingTransporter( + ClientInterface $streamingTransporter + ): self { + $self = clone $this; + $self->streamingTransporter = $streamingTransporter; + + return $self; + } + public function withUriFactory(UriFactoryInterface $uriFactory): self { $self = clone $this; diff --git a/tests/Core/StreamingTransportTest.php b/tests/Core/StreamingTransportTest.php new file mode 100644 index 0000000..16032b7 --- /dev/null +++ b/tests/Core/StreamingTransportTest.php @@ -0,0 +1,122 @@ + true, + 'application/x-ndjson' => true, + 'application/x-ldjson' => true, + 'application/jsonl' => true, + 'application/x-jsonl' => true, + 'text/event-stream; charset=utf-8' => true, + 'application/json' => false, + 'text/plain' => false, + '' => false, + ]; + + foreach ($cases as $accept => $expected) { + $req = $factory->createRequest('GET', 'http://localhost'); + if ('' !== $accept) { + $req = $req->withHeader('Accept', $accept); + } + $this->assertSame( + $expected, + Util::isStreamingRequest($req), + "Accept: '{$accept}'", + ); + } + } + + #[Test] + public function testRoutesNonStreamingRequestToTransporter(): void + { + [$client, $plain, $streaming] = $this->buildClient(); + + $client->request('GET', '/'); + + $this->assertCount(1, $plain->getRequests()); + $this->assertCount(0, $streaming->getRequests()); + } + + #[Test] + public function testRoutesStreamingRequestToStreamingTransporter(): void + { + [$client, $plain, $streaming] = $this->buildClient(); + + $client->request('GET', '/', headers: ['Accept' => 'text/event-stream']); + + $this->assertCount(0, $plain->getRequests()); + $this->assertCount(1, $streaming->getRequests()); + + $sent = $streaming->getRequests()[0]; + $this->assertStringContainsString('text/event-stream', $sent->getHeaderLine('Accept')); + } + + /** + * @return array{BaseClient, MockClient, MockClient} + */ + private function buildClient(): array + { + $plain = new MockClient; + $plain->setDefaultResponse($this->jsonResponse()); + + $streaming = new MockClient; + $streaming->setDefaultResponse($this->sseResponse()); + + $options = RequestOptions::with( + transporter: $plain, + streamingTransporter: $streaming, + uriFactory: Psr17FactoryDiscovery::findUriFactory(), + requestFactory: Psr17FactoryDiscovery::findRequestFactory(), + streamFactory: Psr17FactoryDiscovery::findStreamFactory(), + ); + + $client = new class(headers: [], baseUrl: 'http://localhost', options: $options) extends BaseClient {}; + + return [$client, $plain, $streaming]; + } + + private function jsonResponse(): ResponseInterface + { + $responseFactory = Psr17FactoryDiscovery::findResponseFactory(); + $streamFactory = Psr17FactoryDiscovery::findStreamFactory(); + + return $responseFactory->createResponse(200) + ->withHeader('Content-Type', 'application/json') + ->withBody($streamFactory->createStream('{}')) + ; + } + + private function sseResponse(): ResponseInterface + { + $responseFactory = Psr17FactoryDiscovery::findResponseFactory(); + $streamFactory = Psr17FactoryDiscovery::findStreamFactory(); + + return $responseFactory->createResponse(200) + ->withHeader('Content-Type', 'text/event-stream') + ->withBody($streamFactory->createStream('')) + ; + } +} From b662ff6f0415517e7606c6b90e76acdff37a1114 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 13 May 2026 02:40:29 +0000 Subject: [PATCH 42/48] ci: pin GitHub Actions to commit SHAs Pin all GitHub Actions referenced in generated workflows (both first-party `actions/*` and third-party) to immutable commit SHAs. Updating pinned actions is now a deliberate codegen-side bump rather than implicit on every workflow run. --- .github/workflows/ci.yml | 8 ++++---- .github/workflows/release-doctor.yml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71a6437..3c1d63d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,10 +22,10 @@ jobs: 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: Set up PHP - uses: 'shivammathur/setup-php@v2' + uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 with: php-version: '8.3' @@ -40,10 +40,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/beeper-desktop-api-php' && '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: Set up PHP - uses: 'shivammathur/setup-php@v2' + uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0 with: php-version: '8.3' diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index b0cac61..d8292e2 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'beeper/desktop-api-php' && (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: | From cab2531c989be11a3fdb8ab40e652c412744f480 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 11:33:08 +0000 Subject: [PATCH 43/48] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 2dd3fee..b85c157 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_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-371238be116b1748e82f213ba35b85b0cd574f24e9d9815f73bc743478f23c99.yml openapi_spec_hash: a10246aaf7cdc33b682fc245bd5f893b -config_hash: 72f9d43b9b51a5da912e9f3730e53ae2 +config_hash: 9a5611f899a0fe46abb2a1e463e0ee60 From ad90c3fd37615d13ea180e28f416971e8361dbd5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 19:56:50 +0000 Subject: [PATCH 44/48] Update Desktop API SDKs --- .stats.yml | 8 +- src/App/AppStatusResponse.php | 156 ++++++ src/App/AppStatusResponse/E2ee.php | 260 ++++++++++ src/App/AppStatusResponse/E2ee/Secrets.php | 164 ++++++ src/App/AppStatusResponse/Matrix.php | 111 +++++ src/App/AppStatusResponse/State.php | 25 + src/App/AppStatusResponse/Verification.php | 302 +++++++++++ .../Verification/AvailableAction.php | 22 + .../AppStatusResponse/Verification/Error.php | 88 ++++ .../AppStatusResponse/Verification/Sas.php | 88 ++++ .../AppStatusResponse/Verification/State.php | 27 + .../RecoveryCodeMarkBackedUpResponse.php | 77 +++ .../AppState.php | 158 ++++++ .../AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../AppState/Matrix.php | 111 +++++ .../AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../RecoveryCode/RecoveryCodeVerifyParams.php | 74 +++ .../RecoveryCodeVerifyResponse.php | 77 +++ .../RecoveryCodeVerifyResponse/AppState.php | 158 ++++++ .../AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../AppState/Matrix.php | 111 +++++ .../AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../RecoveryCode/Reset/ResetConfirmParams.php | 74 +++ .../Reset/ResetConfirmResponse.php | 77 +++ .../Reset/ResetConfirmResponse/AppState.php | 158 ++++++ .../ResetConfirmResponse/AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../ResetConfirmResponse/AppState/Matrix.php | 111 +++++ .../ResetConfirmResponse/AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../RecoveryCode/Reset/ResetCreateParams.php | 60 +++ .../RecoveryCode/Reset/ResetNewResponse.php | 97 ++++ .../Reset/ResetNewResponse/AppState.php | 158 ++++++ .../Reset/ResetNewResponse/AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../ResetNewResponse/AppState/Matrix.php | 111 +++++ .../Reset/ResetNewResponse/AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../Qr/QrConfirmScannedResponse.php | 77 +++ .../Qr/QrConfirmScannedResponse/AppState.php | 158 ++++++ .../AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../AppState/Matrix.php | 111 +++++ .../AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + src/App/E2ee/Verification/Qr/QrScanParams.php | 74 +++ .../E2ee/Verification/Qr/QrScanResponse.php | 75 +++ .../Qr/QrScanResponse/AppState.php | 158 ++++++ .../Qr/QrScanResponse/AppState/E2ee.php | 260 ++++++++++ .../QrScanResponse/AppState/E2ee/Secrets.php | 164 ++++++ .../Qr/QrScanResponse/AppState/Matrix.php | 111 +++++ .../Qr/QrScanResponse/AppState/State.php | 25 + .../QrScanResponse/AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../Verification/Sas/SaConfirmResponse.php | 75 +++ .../Sas/SaConfirmResponse/AppState.php | 158 ++++++ .../Sas/SaConfirmResponse/AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../Sas/SaConfirmResponse/AppState/Matrix.php | 111 +++++ .../Sas/SaConfirmResponse/AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../E2ee/Verification/Sas/SaStartResponse.php | 75 +++ .../Sas/SaStartResponse/AppState.php | 158 ++++++ .../Sas/SaStartResponse/AppState/E2ee.php | 260 ++++++++++ .../SaStartResponse/AppState/E2ee/Secrets.php | 164 ++++++ .../Sas/SaStartResponse/AppState/Matrix.php | 111 +++++ .../Sas/SaStartResponse/AppState/State.php | 25 + .../SaStartResponse/AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../VerificationAcceptResponse.php | 77 +++ .../VerificationAcceptResponse/AppState.php | 158 ++++++ .../AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../AppState/Matrix.php | 111 +++++ .../AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../Verification/VerificationCancelParams.php | 82 +++ .../VerificationCancelResponse.php | 77 +++ .../VerificationCancelResponse/AppState.php | 158 ++++++ .../AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../AppState/Matrix.php | 111 +++++ .../AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../Verification/VerificationCreateParams.php | 60 +++ .../Verification/VerificationNewResponse.php | 97 ++++ .../VerificationNewResponse/AppState.php | 158 ++++++ .../VerificationNewResponse/AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../AppState/Matrix.php | 111 +++++ .../AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + src/App/Login/LoginEmailParams.php | 92 ++++ src/App/Login/LoginRegisterParams.php | 140 ++++++ src/App/Login/LoginRegisterResponse.php | 131 +++++ .../Login/LoginRegisterResponse/AppState.php | 159 ++++++ .../LoginRegisterResponse/AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../LoginRegisterResponse/AppState/Matrix.php | 111 +++++ .../LoginRegisterResponse/AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../LoginRegisterResponse/DesktopAPI.php | 126 +++++ .../DesktopAPI/Scope.php | 13 + .../DesktopAPI/TokenType.php | 13 + .../Login/LoginRegisterResponse/Matrix.php | 134 +++++ src/App/Login/LoginResponseParams.php | 94 ++++ src/App/Login/LoginResponseResponse.php | 31 ++ .../LoginResponseResponse/UnionMember0.php | 128 +++++ .../UnionMember0/AppState.php | 159 ++++++ .../UnionMember0/AppState/E2ee.php | 260 ++++++++++ .../UnionMember0/AppState/E2ee/Secrets.php | 164 ++++++ .../UnionMember0/AppState/Matrix.php | 111 +++++ .../UnionMember0/AppState/State.php | 25 + .../UnionMember0/AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../UnionMember0/DesktopAPI.php | 126 +++++ .../UnionMember0/DesktopAPI/Scope.php | 13 + .../UnionMember0/DesktopAPI/TokenType.php | 13 + .../UnionMember0/Matrix.php | 134 +++++ .../LoginResponseResponse/UnionMember1.php | 171 +++++++ .../UnionMember1/Copy.php | 163 ++++++ .../UnionMember1/Copy/Submit.php | 13 + .../UnionMember1/Copy/Terms.php | 13 + .../UnionMember1/Copy/Title.php | 13 + .../UnionMember1/Copy/UsernamePlaceholder.php | 13 + src/App/Login/LoginStartResponse.php | 94 ++++ src/App/LoginRegistrationRequiredResponse.php | 171 +++++++ .../Copy.php | 163 ++++++ .../Copy/Submit.php | 13 + .../Copy/Terms.php | 13 + .../Copy/Title.php | 13 + .../Copy/UsernamePlaceholder.php | 13 + src/App/LoginResponse.php | 128 +++++ src/App/LoginResponse/AppState.php | 159 ++++++ src/App/LoginResponse/AppState/E2ee.php | 260 ++++++++++ .../LoginResponse/AppState/E2ee/Secrets.php | 164 ++++++ src/App/LoginResponse/AppState/Matrix.php | 111 +++++ src/App/LoginResponse/AppState/State.php | 25 + .../LoginResponse/AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + src/App/LoginResponse/DesktopAPI.php | 126 +++++ src/App/LoginResponse/DesktopAPI/Scope.php | 13 + .../LoginResponse/DesktopAPI/TokenType.php | 13 + src/App/LoginResponse/Matrix.php | 134 +++++ src/App/LoginResponseOutput.php | 31 ++ src/App/LoginResponseOutput/UnionMember0.php | 128 +++++ .../UnionMember0/AppState.php | 159 ++++++ .../UnionMember0/AppState/E2ee.php | 260 ++++++++++ .../UnionMember0/AppState/E2ee/Secrets.php | 164 ++++++ .../UnionMember0/AppState/Matrix.php | 111 +++++ .../UnionMember0/AppState/State.php | 25 + .../UnionMember0/AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + .../UnionMember0/DesktopAPI.php | 126 +++++ .../UnionMember0/DesktopAPI/Scope.php | 13 + .../UnionMember0/DesktopAPI/TokenType.php | 13 + .../UnionMember0/Matrix.php | 134 +++++ src/App/LoginResponseOutput/UnionMember1.php | 171 +++++++ .../LoginResponseOutput/UnionMember1/Copy.php | 163 ++++++ .../UnionMember1/Copy/Submit.php | 13 + .../UnionMember1/Copy/Terms.php | 13 + .../UnionMember1/Copy/Title.php | 13 + .../UnionMember1/Copy/UsernamePlaceholder.php | 13 + src/App/RecoveryCodeResetResponse.php | 97 ++++ .../RecoveryCodeResetResponse/AppState.php | 158 ++++++ .../AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../AppState/Matrix.php | 111 +++++ .../AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + src/App/StartVerificationResponse.php | 97 ++++ .../StartVerificationResponse/AppState.php | 158 ++++++ .../AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../AppState/Matrix.php | 111 +++++ .../AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + src/App/StateMutationResponse.php | 77 +++ src/App/StateMutationResponse/AppState.php | 158 ++++++ .../StateMutationResponse/AppState/E2ee.php | 260 ++++++++++ .../AppState/E2ee/Secrets.php | 164 ++++++ .../StateMutationResponse/AppState/Matrix.php | 111 +++++ .../StateMutationResponse/AppState/State.php | 25 + .../AppState/Verification.php | 302 +++++++++++ .../AppState/Verification/AvailableAction.php | 22 + .../AppState/Verification/Error.php | 88 ++++ .../AppState/Verification/Sas.php | 88 ++++ .../AppState/Verification/State.php | 27 + src/AppStateSnapshot.php | 156 ++++++ src/AppStateSnapshot/E2ee.php | 260 ++++++++++ src/AppStateSnapshot/E2ee/Secrets.php | 164 ++++++ src/AppStateSnapshot/Matrix.php | 111 +++++ src/AppStateSnapshot/State.php | 25 + src/AppStateSnapshot/Verification.php | 300 +++++++++++ .../Verification/AvailableAction.php | 22 + src/AppStateSnapshot/Verification/Error.php | 88 ++++ src/AppStateSnapshot/Verification/Sas.php | 88 ++++ src/AppStateSnapshot/Verification/State.php | 27 + src/Bridges/BridgeAvailability.php | 248 +++++++++ src/Bridges/BridgeAvailability/Bridge.php | 118 +++++ .../BridgeAvailability/Bridge/Provider.php | 19 + src/Bridges/BridgeAvailability/Status.php | 19 + src/Bridges/BridgeListResponse.php | 74 +++ src/Client.php | 21 + .../Bridges/Auth/AuthListFlowsResponse.php | 59 +++ .../Auth/AuthListFlowsResponse/Flow.php | 109 ++++ .../Bridges/Auth/AuthListLoginsResponse.php | 54 ++ src/Matrix/Bridges/Auth/AuthLogoutParams.php | 68 +++ .../Bridges/Auth/AuthStartLoginParams.php | 106 ++++ .../Bridges/Auth/AuthStartLoginResponse.php | 42 ++ .../AuthStartLoginResponse/UnionMember0.php | 159 ++++++ .../UnionMember0/DisplayAndWait.php | 120 +++++ .../UnionMember0/DisplayAndWait/Type.php | 19 + .../AuthStartLoginResponse/UnionMember1.php | 158 ++++++ .../UnionMember1/UserInput.php | 109 ++++ .../UnionMember1/UserInput/Attachment.php | 148 ++++++ .../UserInput/Attachment/Info.php | 116 +++++ .../UserInput/Attachment/Type.php | 15 + .../UnionMember1/UserInput/Field.php | 207 ++++++++ .../UnionMember1/UserInput/Field/Type.php | 29 ++ .../AuthStartLoginResponse/UnionMember2.php | 158 ++++++ .../UnionMember2/Cookies.php | 176 +++++++ .../UnionMember2/Cookies/Field.php | 142 ++++++ .../UnionMember2/Cookies/Field/Type.php | 21 + .../AuthStartLoginResponse/UnionMember3.php | 158 ++++++ .../UnionMember3/Complete.php | 56 +++ .../Bridges/Auth/AuthSubmitCookiesParams.php | 106 ++++ .../Auth/AuthSubmitCookiesResponse.php | 42 ++ .../UnionMember0.php | 159 ++++++ .../UnionMember0/DisplayAndWait.php | 120 +++++ .../UnionMember0/DisplayAndWait/Type.php | 19 + .../UnionMember1.php | 158 ++++++ .../UnionMember1/UserInput.php | 109 ++++ .../UnionMember1/UserInput/Attachment.php | 148 ++++++ .../UserInput/Attachment/Info.php | 116 +++++ .../UserInput/Attachment/Type.php | 15 + .../UnionMember1/UserInput/Field.php | 207 ++++++++ .../UnionMember1/UserInput/Field/Type.php | 29 ++ .../UnionMember2.php | 158 ++++++ .../UnionMember2/Cookies.php | 176 +++++++ .../UnionMember2/Cookies/Field.php | 142 ++++++ .../UnionMember2/Cookies/Field/Type.php | 21 + .../UnionMember3.php | 158 ++++++ .../UnionMember3/Complete.php | 56 +++ .../Auth/AuthSubmitUserInputParams.php | 106 ++++ .../Auth/AuthSubmitUserInputResponse.php | 42 ++ .../UnionMember0.php | 159 ++++++ .../UnionMember0/DisplayAndWait.php | 120 +++++ .../UnionMember0/DisplayAndWait/Type.php | 19 + .../UnionMember1.php | 158 ++++++ .../UnionMember1/UserInput.php | 109 ++++ .../UnionMember1/UserInput/Attachment.php | 148 ++++++ .../UserInput/Attachment/Info.php | 116 +++++ .../UserInput/Attachment/Type.php | 15 + .../UnionMember1/UserInput/Field.php | 207 ++++++++ .../UnionMember1/UserInput/Field/Type.php | 29 ++ .../UnionMember2.php | 158 ++++++ .../UnionMember2/Cookies.php | 176 +++++++ .../UnionMember2/Cookies/Field.php | 142 ++++++ .../UnionMember2/Cookies/Field/Type.php | 21 + .../UnionMember3.php | 158 ++++++ .../UnionMember3/Complete.php | 56 +++ .../Bridges/Auth/AuthWaitForStepParams.php | 82 +++ .../Bridges/Auth/AuthWaitForStepResponse.php | 42 ++ .../AuthWaitForStepResponse/UnionMember0.php | 159 ++++++ .../UnionMember0/DisplayAndWait.php | 120 +++++ .../UnionMember0/DisplayAndWait/Type.php | 19 + .../AuthWaitForStepResponse/UnionMember1.php | 158 ++++++ .../UnionMember1/UserInput.php | 109 ++++ .../UnionMember1/UserInput/Attachment.php | 148 ++++++ .../UserInput/Attachment/Info.php | 116 +++++ .../UserInput/Attachment/Type.php | 15 + .../UnionMember1/UserInput/Field.php | 207 ++++++++ .../UnionMember1/UserInput/Field/Type.php | 29 ++ .../AuthWaitForStepResponse/UnionMember2.php | 158 ++++++ .../UnionMember2/Cookies.php | 176 +++++++ .../UnionMember2/Cookies/Field.php | 142 ++++++ .../UnionMember2/Cookies/Field/Type.php | 21 + .../AuthWaitForStepResponse/UnionMember3.php | 158 ++++++ .../UnionMember3/Complete.php | 56 +++ .../Bridges/Auth/AuthWhoamiResponse.php | 229 +++++++++ .../Bridges/Auth/AuthWhoamiResponse/Login.php | 167 +++++++ .../Auth/AuthWhoamiResponse/Login/Profile.php | 139 ++++++ .../Auth/AuthWhoamiResponse/Login/State.php | 182 +++++++ .../Login/State/StateEvent.php | 21 + .../Auth/AuthWhoamiResponse/LoginFlow.php | 111 +++++ .../Auth/AuthWhoamiResponse/Network.php | 164 ++++++ .../Bridges/Contacts/ContactListParams.php | 60 +++ .../Bridges/Contacts/ContactListResponse.php | 59 +++ .../Contacts/ContactListResponse/Contact.php | 181 +++++++ .../Bridges/Rooms/RoomCreateDmParams.php | 90 ++++ .../Bridges/Rooms/RoomCreateGroupParams.php | 296 +++++++++++ .../Rooms/RoomCreateGroupParams/Avatar.php | 50 ++ .../Rooms/RoomCreateGroupParams/Disappear.php | 62 +++ .../Rooms/RoomCreateGroupParams/Name.php | 50 ++ .../Rooms/RoomCreateGroupParams/Topic.php | 50 ++ .../Bridges/Rooms/RoomNewDmResponse.php | 181 +++++++ .../Bridges/Rooms/RoomNewGroupResponse.php | 88 ++++ .../Bridges/Users/UserResolveParams.php | 90 ++++ .../Bridges/Users/UserResolveResponse.php | 181 +++++++ src/Matrix/Bridges/Users/UserSearchParams.php | 82 +++ .../Bridges/Users/UserSearchResponse.php | 59 +++ .../Users/UserSearchResponse/Result.php | 181 +++++++ .../AccountData/AccountDataRetrieveParams.php | 83 +++ .../AccountData/AccountDataUpdateParams.php | 99 ++++ src/Matrix/Rooms/Events/EventGetResponse.php | 245 +++++++++ .../Events/EventGetResponse/Unsigned.php | 167 +++++++ .../Rooms/Events/EventRetrieveParams.php | 69 +++ src/Matrix/Rooms/RoomCreateParams.php | 471 ++++++++++++++++++ .../Rooms/RoomCreateParams/InitialState.php | 111 +++++ .../Rooms/RoomCreateParams/Invite3pid.php | 138 +++++ src/Matrix/Rooms/RoomCreateParams/Preset.php | 23 + .../Rooms/RoomCreateParams/Visibility.php | 17 + src/Matrix/Rooms/RoomJoinParams.php | 131 +++++ .../Rooms/RoomJoinParams/ThirdPartySigned.php | 145 ++++++ src/Matrix/Rooms/RoomJoinResponse.php | 68 +++ src/Matrix/Rooms/RoomLeaveParams.php | 79 +++ src/Matrix/Rooms/RoomNewResponse.php | 70 +++ .../Rooms/State/StateListResponseItem.php | 245 +++++++++ .../State/StateListResponseItem/Unsigned.php | 167 +++++++ .../Rooms/State/StateRetrieveParams.php | 121 +++++ .../State/StateRetrieveParams/Format.php | 18 + .../AccountData/AccountDataRetrieveParams.php | 69 +++ .../AccountData/AccountDataUpdateParams.php | 83 +++ src/Matrix/Users/UserGetProfileResponse.php | 95 ++++ .../App/E2ee/RecoveryCode/ResetContract.php | 42 ++ .../E2ee/RecoveryCode/ResetRawContract.php | 49 ++ .../App/E2ee/RecoveryCodeContract.php | 40 ++ .../App/E2ee/RecoveryCodeRawContract.php | 46 ++ .../App/E2ee/Verification/QrContract.php | 42 ++ .../App/E2ee/Verification/QrRawContract.php | 48 ++ .../App/E2ee/Verification/SasContract.php | 42 ++ .../App/E2ee/Verification/SasRawContract.php | 47 ++ .../App/E2ee/VerificationContract.php | 60 +++ .../App/E2ee/VerificationRawContract.php | 67 +++ src/ServiceContracts/App/E2eeContract.php | 7 + src/ServiceContracts/App/E2eeRawContract.php | 7 + src/ServiceContracts/App/LoginContract.php | 78 +++ src/ServiceContracts/App/LoginRawContract.php | 80 +++ src/ServiceContracts/AppContract.php | 26 + src/ServiceContracts/AppRawContract.php | 29 ++ src/ServiceContracts/BridgesContract.php | 26 + src/ServiceContracts/BridgesRawContract.php | 29 ++ .../Matrix/Bridges/AuthContract.php | 147 ++++++ .../Matrix/Bridges/AuthRawContract.php | 157 ++++++ .../Matrix/Bridges/CapabilitiesContract.php | 29 ++ .../Bridges/CapabilitiesRawContract.php | 30 ++ .../Matrix/Bridges/ContactsContract.php | 30 ++ .../Matrix/Bridges/ContactsRawContract.php | 34 ++ .../Matrix/Bridges/RoomsContract.php | 77 +++ .../Matrix/Bridges/RoomsRawContract.php | 53 ++ .../Matrix/Bridges/UsersContract.php | 50 ++ .../Matrix/Bridges/UsersRawContract.php | 53 ++ .../Matrix/BridgesContract.php | 7 + .../Matrix/BridgesRawContract.php | 7 + .../Matrix/Rooms/AccountDataContract.php | 54 ++ .../Matrix/Rooms/AccountDataRawContract.php | 53 ++ .../Matrix/Rooms/EventsContract.php | 30 ++ .../Matrix/Rooms/EventsRawContract.php | 34 ++ .../Matrix/Rooms/StateContract.php | 56 +++ .../Matrix/Rooms/StateRawContract.php | 50 ++ src/ServiceContracts/Matrix/RoomsContract.php | 147 ++++++ .../Matrix/RoomsRawContract.php | 69 +++ .../Matrix/Users/AccountDataContract.php | 50 ++ .../Matrix/Users/AccountDataRawContract.php | 53 ++ src/ServiceContracts/Matrix/UsersContract.php | 28 ++ .../Matrix/UsersRawContract.php | 31 ++ src/ServiceContracts/MatrixContract.php | 7 + src/ServiceContracts/MatrixRawContract.php | 7 + .../App/E2ee/RecoveryCode/ResetRawService.php | 91 ++++ .../App/E2ee/RecoveryCode/ResetService.php | 78 +++ .../App/E2ee/RecoveryCodeRawService.php | 82 +++ src/Services/App/E2ee/RecoveryCodeService.php | 81 +++ .../App/E2ee/Verification/QrRawService.php | 86 ++++ .../App/E2ee/Verification/QrService.php | 76 +++ .../App/E2ee/Verification/SasRawService.php | 77 +++ .../App/E2ee/Verification/SasService.php | 73 +++ .../App/E2ee/VerificationRawService.php | 119 +++++ src/Services/App/E2ee/VerificationService.php | 117 +++++ src/Services/App/E2eeRawService.php | 20 + src/Services/App/E2eeService.php | 41 ++ src/Services/App/LoginRawService.php | 155 ++++++ src/Services/App/LoginService.php | 139 ++++++ src/Services/AppRawService.php | 49 ++ src/Services/AppService.php | 64 +++ src/Services/BridgesRawService.php | 49 ++ src/Services/BridgesService.php | 50 ++ .../Matrix/Bridges/AuthRawService.php | 358 +++++++++++++ src/Services/Matrix/Bridges/AuthService.php | 265 ++++++++++ .../Matrix/Bridges/CapabilitiesRawService.php | 54 ++ .../Matrix/Bridges/CapabilitiesService.php | 53 ++ .../Matrix/Bridges/ContactsRawService.php | 64 +++ .../Matrix/Bridges/ContactsService.php | 57 +++ .../Matrix/Bridges/RoomsRawService.php | 136 +++++ src/Services/Matrix/Bridges/RoomsService.php | 129 +++++ .../Matrix/Bridges/UsersRawService.php | 110 ++++ src/Services/Matrix/Bridges/UsersService.php | 88 ++++ src/Services/Matrix/BridgesRawService.php | 20 + src/Services/Matrix/BridgesService.php | 62 +++ .../Matrix/Rooms/AccountDataRawService.php | 118 +++++ .../Matrix/Rooms/AccountDataService.php | 93 ++++ .../Matrix/Rooms/EventsRawService.php | 60 +++ src/Services/Matrix/Rooms/EventsService.php | 56 +++ src/Services/Matrix/Rooms/StateRawService.php | 101 ++++ src/Services/Matrix/Rooms/StateService.php | 93 ++++ src/Services/Matrix/RoomsRawService.php | 232 +++++++++ src/Services/Matrix/RoomsService.php | 312 ++++++++++++ .../Matrix/Users/AccountDataRawService.php | 103 ++++ .../Matrix/Users/AccountDataService.php | 88 ++++ src/Services/Matrix/UsersRawService.php | 49 ++ src/Services/Matrix/UsersService.php | 57 +++ src/Services/MatrixRawService.php | 20 + src/Services/MatrixService.php | 48 ++ .../App/E2ee/RecoveryCode/ResetTest.php | 61 +++ tests/Services/App/E2ee/RecoveryCodeTest.php | 57 +++ .../Services/App/E2ee/Verification/QrTest.php | 57 +++ .../App/E2ee/Verification/SasTest.php | 48 ++ tests/Services/App/E2ee/VerificationTest.php | 58 +++ tests/Services/App/LoginTest.php | 115 +++++ tests/Services/AppTest.php | 38 ++ tests/Services/BridgesTest.php | 38 ++ tests/Services/Matrix/Bridges/AuthTest.php | 189 +++++++ .../Matrix/Bridges/CapabilitiesTest.php | 39 ++ .../Services/Matrix/Bridges/ContactsTest.php | 38 ++ tests/Services/Matrix/Bridges/RoomsTest.php | 89 ++++ tests/Services/Matrix/Bridges/UsersTest.php | 64 +++ .../Services/Matrix/Rooms/AccountDataTest.php | 82 +++ tests/Services/Matrix/Rooms/EventsTest.php | 53 ++ tests/Services/Matrix/Rooms/StateTest.php | 66 +++ tests/Services/Matrix/RoomsTest.php | 57 +++ .../Services/Matrix/Users/AccountDataTest.php | 78 +++ tests/Services/Matrix/UsersTest.php | 40 ++ 499 files changed, 51433 insertions(+), 4 deletions(-) create mode 100644 src/App/AppStatusResponse.php create mode 100644 src/App/AppStatusResponse/E2ee.php create mode 100644 src/App/AppStatusResponse/E2ee/Secrets.php create mode 100644 src/App/AppStatusResponse/Matrix.php create mode 100644 src/App/AppStatusResponse/State.php create mode 100644 src/App/AppStatusResponse/Verification.php create mode 100644 src/App/AppStatusResponse/Verification/AvailableAction.php create mode 100644 src/App/AppStatusResponse/Verification/Error.php create mode 100644 src/App/AppStatusResponse/Verification/Sas.php create mode 100644 src/App/AppStatusResponse/Verification/State.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/State.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyParams.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/State.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmParams.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/State.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetCreateParams.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/State.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/State.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanParams.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState/State.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/State.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState/State.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState/State.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/Verification/VerificationCancelParams.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState/State.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/State.php create mode 100644 src/App/E2ee/Verification/VerificationCreateParams.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState/E2ee.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState/Matrix.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState/State.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/Error.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/Sas.php create mode 100644 src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/State.php create mode 100644 src/App/Login/LoginEmailParams.php create mode 100644 src/App/Login/LoginRegisterParams.php create mode 100644 src/App/Login/LoginRegisterResponse.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState/E2ee.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState/Matrix.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState/State.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState/Verification.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState/Verification/Error.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState/Verification/Sas.php create mode 100644 src/App/Login/LoginRegisterResponse/AppState/Verification/State.php create mode 100644 src/App/Login/LoginRegisterResponse/DesktopAPI.php create mode 100644 src/App/Login/LoginRegisterResponse/DesktopAPI/Scope.php create mode 100644 src/App/Login/LoginRegisterResponse/DesktopAPI/TokenType.php create mode 100644 src/App/Login/LoginRegisterResponse/Matrix.php create mode 100644 src/App/Login/LoginResponseParams.php create mode 100644 src/App/Login/LoginResponseResponse.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState/E2ee.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState/E2ee/Secrets.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState/Matrix.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState/State.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/AvailableAction.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/Error.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/Sas.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/State.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/DesktopAPI.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/DesktopAPI/Scope.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/DesktopAPI/TokenType.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember0/Matrix.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember1.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember1/Copy.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember1/Copy/Submit.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember1/Copy/Terms.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember1/Copy/Title.php create mode 100644 src/App/Login/LoginResponseResponse/UnionMember1/Copy/UsernamePlaceholder.php create mode 100644 src/App/Login/LoginStartResponse.php create mode 100644 src/App/LoginRegistrationRequiredResponse.php create mode 100644 src/App/LoginRegistrationRequiredResponse/Copy.php create mode 100644 src/App/LoginRegistrationRequiredResponse/Copy/Submit.php create mode 100644 src/App/LoginRegistrationRequiredResponse/Copy/Terms.php create mode 100644 src/App/LoginRegistrationRequiredResponse/Copy/Title.php create mode 100644 src/App/LoginRegistrationRequiredResponse/Copy/UsernamePlaceholder.php create mode 100644 src/App/LoginResponse.php create mode 100644 src/App/LoginResponse/AppState.php create mode 100644 src/App/LoginResponse/AppState/E2ee.php create mode 100644 src/App/LoginResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/LoginResponse/AppState/Matrix.php create mode 100644 src/App/LoginResponse/AppState/State.php create mode 100644 src/App/LoginResponse/AppState/Verification.php create mode 100644 src/App/LoginResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/LoginResponse/AppState/Verification/Error.php create mode 100644 src/App/LoginResponse/AppState/Verification/Sas.php create mode 100644 src/App/LoginResponse/AppState/Verification/State.php create mode 100644 src/App/LoginResponse/DesktopAPI.php create mode 100644 src/App/LoginResponse/DesktopAPI/Scope.php create mode 100644 src/App/LoginResponse/DesktopAPI/TokenType.php create mode 100644 src/App/LoginResponse/Matrix.php create mode 100644 src/App/LoginResponseOutput.php create mode 100644 src/App/LoginResponseOutput/UnionMember0.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState/E2ee.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState/E2ee/Secrets.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState/Matrix.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState/State.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState/Verification.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState/Verification/AvailableAction.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState/Verification/Error.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState/Verification/Sas.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/AppState/Verification/State.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/DesktopAPI.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/DesktopAPI/Scope.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/DesktopAPI/TokenType.php create mode 100644 src/App/LoginResponseOutput/UnionMember0/Matrix.php create mode 100644 src/App/LoginResponseOutput/UnionMember1.php create mode 100644 src/App/LoginResponseOutput/UnionMember1/Copy.php create mode 100644 src/App/LoginResponseOutput/UnionMember1/Copy/Submit.php create mode 100644 src/App/LoginResponseOutput/UnionMember1/Copy/Terms.php create mode 100644 src/App/LoginResponseOutput/UnionMember1/Copy/Title.php create mode 100644 src/App/LoginResponseOutput/UnionMember1/Copy/UsernamePlaceholder.php create mode 100644 src/App/RecoveryCodeResetResponse.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState/E2ee.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState/Matrix.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState/State.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState/Verification.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState/Verification/Error.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState/Verification/Sas.php create mode 100644 src/App/RecoveryCodeResetResponse/AppState/Verification/State.php create mode 100644 src/App/StartVerificationResponse.php create mode 100644 src/App/StartVerificationResponse/AppState.php create mode 100644 src/App/StartVerificationResponse/AppState/E2ee.php create mode 100644 src/App/StartVerificationResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/StartVerificationResponse/AppState/Matrix.php create mode 100644 src/App/StartVerificationResponse/AppState/State.php create mode 100644 src/App/StartVerificationResponse/AppState/Verification.php create mode 100644 src/App/StartVerificationResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/StartVerificationResponse/AppState/Verification/Error.php create mode 100644 src/App/StartVerificationResponse/AppState/Verification/Sas.php create mode 100644 src/App/StartVerificationResponse/AppState/Verification/State.php create mode 100644 src/App/StateMutationResponse.php create mode 100644 src/App/StateMutationResponse/AppState.php create mode 100644 src/App/StateMutationResponse/AppState/E2ee.php create mode 100644 src/App/StateMutationResponse/AppState/E2ee/Secrets.php create mode 100644 src/App/StateMutationResponse/AppState/Matrix.php create mode 100644 src/App/StateMutationResponse/AppState/State.php create mode 100644 src/App/StateMutationResponse/AppState/Verification.php create mode 100644 src/App/StateMutationResponse/AppState/Verification/AvailableAction.php create mode 100644 src/App/StateMutationResponse/AppState/Verification/Error.php create mode 100644 src/App/StateMutationResponse/AppState/Verification/Sas.php create mode 100644 src/App/StateMutationResponse/AppState/Verification/State.php create mode 100644 src/AppStateSnapshot.php create mode 100644 src/AppStateSnapshot/E2ee.php create mode 100644 src/AppStateSnapshot/E2ee/Secrets.php create mode 100644 src/AppStateSnapshot/Matrix.php create mode 100644 src/AppStateSnapshot/State.php create mode 100644 src/AppStateSnapshot/Verification.php create mode 100644 src/AppStateSnapshot/Verification/AvailableAction.php create mode 100644 src/AppStateSnapshot/Verification/Error.php create mode 100644 src/AppStateSnapshot/Verification/Sas.php create mode 100644 src/AppStateSnapshot/Verification/State.php create mode 100644 src/Bridges/BridgeAvailability.php create mode 100644 src/Bridges/BridgeAvailability/Bridge.php create mode 100644 src/Bridges/BridgeAvailability/Bridge/Provider.php create mode 100644 src/Bridges/BridgeAvailability/Status.php create mode 100644 src/Bridges/BridgeListResponse.php create mode 100644 src/Matrix/Bridges/Auth/AuthListFlowsResponse.php create mode 100644 src/Matrix/Bridges/Auth/AuthListFlowsResponse/Flow.php create mode 100644 src/Matrix/Bridges/Auth/AuthListLoginsResponse.php create mode 100644 src/Matrix/Bridges/Auth/AuthLogoutParams.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginParams.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0/DisplayAndWait.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0/DisplayAndWait/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment/Info.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Field.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Field/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies/Field.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies/Field/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember3.php create mode 100644 src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember3/Complete.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesParams.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0/DisplayAndWait.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0/DisplayAndWait/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment/Info.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Field.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Field/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies/Field.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies/Field/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember3.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember3/Complete.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputParams.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0/DisplayAndWait.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0/DisplayAndWait/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment/Info.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Field.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Field/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies/Field.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies/Field/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember3.php create mode 100644 src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember3/Complete.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepParams.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0/DisplayAndWait.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0/DisplayAndWait/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment/Info.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Field.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Field/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies/Field.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies/Field/Type.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember3.php create mode 100644 src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember3/Complete.php create mode 100644 src/Matrix/Bridges/Auth/AuthWhoamiResponse.php create mode 100644 src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login.php create mode 100644 src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/Profile.php create mode 100644 src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/State.php create mode 100644 src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/State/StateEvent.php create mode 100644 src/Matrix/Bridges/Auth/AuthWhoamiResponse/LoginFlow.php create mode 100644 src/Matrix/Bridges/Auth/AuthWhoamiResponse/Network.php create mode 100644 src/Matrix/Bridges/Contacts/ContactListParams.php create mode 100644 src/Matrix/Bridges/Contacts/ContactListResponse.php create mode 100644 src/Matrix/Bridges/Contacts/ContactListResponse/Contact.php create mode 100644 src/Matrix/Bridges/Rooms/RoomCreateDmParams.php create mode 100644 src/Matrix/Bridges/Rooms/RoomCreateGroupParams.php create mode 100644 src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Avatar.php create mode 100644 src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Disappear.php create mode 100644 src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Name.php create mode 100644 src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Topic.php create mode 100644 src/Matrix/Bridges/Rooms/RoomNewDmResponse.php create mode 100644 src/Matrix/Bridges/Rooms/RoomNewGroupResponse.php create mode 100644 src/Matrix/Bridges/Users/UserResolveParams.php create mode 100644 src/Matrix/Bridges/Users/UserResolveResponse.php create mode 100644 src/Matrix/Bridges/Users/UserSearchParams.php create mode 100644 src/Matrix/Bridges/Users/UserSearchResponse.php create mode 100644 src/Matrix/Bridges/Users/UserSearchResponse/Result.php create mode 100644 src/Matrix/Rooms/AccountData/AccountDataRetrieveParams.php create mode 100644 src/Matrix/Rooms/AccountData/AccountDataUpdateParams.php create mode 100644 src/Matrix/Rooms/Events/EventGetResponse.php create mode 100644 src/Matrix/Rooms/Events/EventGetResponse/Unsigned.php create mode 100644 src/Matrix/Rooms/Events/EventRetrieveParams.php create mode 100644 src/Matrix/Rooms/RoomCreateParams.php create mode 100644 src/Matrix/Rooms/RoomCreateParams/InitialState.php create mode 100644 src/Matrix/Rooms/RoomCreateParams/Invite3pid.php create mode 100644 src/Matrix/Rooms/RoomCreateParams/Preset.php create mode 100644 src/Matrix/Rooms/RoomCreateParams/Visibility.php create mode 100644 src/Matrix/Rooms/RoomJoinParams.php create mode 100644 src/Matrix/Rooms/RoomJoinParams/ThirdPartySigned.php create mode 100644 src/Matrix/Rooms/RoomJoinResponse.php create mode 100644 src/Matrix/Rooms/RoomLeaveParams.php create mode 100644 src/Matrix/Rooms/RoomNewResponse.php create mode 100644 src/Matrix/Rooms/State/StateListResponseItem.php create mode 100644 src/Matrix/Rooms/State/StateListResponseItem/Unsigned.php create mode 100644 src/Matrix/Rooms/State/StateRetrieveParams.php create mode 100644 src/Matrix/Rooms/State/StateRetrieveParams/Format.php create mode 100644 src/Matrix/Users/AccountData/AccountDataRetrieveParams.php create mode 100644 src/Matrix/Users/AccountData/AccountDataUpdateParams.php create mode 100644 src/Matrix/Users/UserGetProfileResponse.php create mode 100644 src/ServiceContracts/App/E2ee/RecoveryCode/ResetContract.php create mode 100644 src/ServiceContracts/App/E2ee/RecoveryCode/ResetRawContract.php create mode 100644 src/ServiceContracts/App/E2ee/RecoveryCodeContract.php create mode 100644 src/ServiceContracts/App/E2ee/RecoveryCodeRawContract.php create mode 100644 src/ServiceContracts/App/E2ee/Verification/QrContract.php create mode 100644 src/ServiceContracts/App/E2ee/Verification/QrRawContract.php create mode 100644 src/ServiceContracts/App/E2ee/Verification/SasContract.php create mode 100644 src/ServiceContracts/App/E2ee/Verification/SasRawContract.php create mode 100644 src/ServiceContracts/App/E2ee/VerificationContract.php create mode 100644 src/ServiceContracts/App/E2ee/VerificationRawContract.php create mode 100644 src/ServiceContracts/App/E2eeContract.php create mode 100644 src/ServiceContracts/App/E2eeRawContract.php create mode 100644 src/ServiceContracts/App/LoginContract.php create mode 100644 src/ServiceContracts/App/LoginRawContract.php create mode 100644 src/ServiceContracts/AppContract.php create mode 100644 src/ServiceContracts/AppRawContract.php create mode 100644 src/ServiceContracts/BridgesContract.php create mode 100644 src/ServiceContracts/BridgesRawContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/AuthContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/AuthRawContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/CapabilitiesContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/CapabilitiesRawContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/ContactsContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/ContactsRawContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/RoomsContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/RoomsRawContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/UsersContract.php create mode 100644 src/ServiceContracts/Matrix/Bridges/UsersRawContract.php create mode 100644 src/ServiceContracts/Matrix/BridgesContract.php create mode 100644 src/ServiceContracts/Matrix/BridgesRawContract.php create mode 100644 src/ServiceContracts/Matrix/Rooms/AccountDataContract.php create mode 100644 src/ServiceContracts/Matrix/Rooms/AccountDataRawContract.php create mode 100644 src/ServiceContracts/Matrix/Rooms/EventsContract.php create mode 100644 src/ServiceContracts/Matrix/Rooms/EventsRawContract.php create mode 100644 src/ServiceContracts/Matrix/Rooms/StateContract.php create mode 100644 src/ServiceContracts/Matrix/Rooms/StateRawContract.php create mode 100644 src/ServiceContracts/Matrix/RoomsContract.php create mode 100644 src/ServiceContracts/Matrix/RoomsRawContract.php create mode 100644 src/ServiceContracts/Matrix/Users/AccountDataContract.php create mode 100644 src/ServiceContracts/Matrix/Users/AccountDataRawContract.php create mode 100644 src/ServiceContracts/Matrix/UsersContract.php create mode 100644 src/ServiceContracts/Matrix/UsersRawContract.php create mode 100644 src/ServiceContracts/MatrixContract.php create mode 100644 src/ServiceContracts/MatrixRawContract.php create mode 100644 src/Services/App/E2ee/RecoveryCode/ResetRawService.php create mode 100644 src/Services/App/E2ee/RecoveryCode/ResetService.php create mode 100644 src/Services/App/E2ee/RecoveryCodeRawService.php create mode 100644 src/Services/App/E2ee/RecoveryCodeService.php create mode 100644 src/Services/App/E2ee/Verification/QrRawService.php create mode 100644 src/Services/App/E2ee/Verification/QrService.php create mode 100644 src/Services/App/E2ee/Verification/SasRawService.php create mode 100644 src/Services/App/E2ee/Verification/SasService.php create mode 100644 src/Services/App/E2ee/VerificationRawService.php create mode 100644 src/Services/App/E2ee/VerificationService.php create mode 100644 src/Services/App/E2eeRawService.php create mode 100644 src/Services/App/E2eeService.php create mode 100644 src/Services/App/LoginRawService.php create mode 100644 src/Services/App/LoginService.php create mode 100644 src/Services/AppRawService.php create mode 100644 src/Services/AppService.php create mode 100644 src/Services/BridgesRawService.php create mode 100644 src/Services/BridgesService.php create mode 100644 src/Services/Matrix/Bridges/AuthRawService.php create mode 100644 src/Services/Matrix/Bridges/AuthService.php create mode 100644 src/Services/Matrix/Bridges/CapabilitiesRawService.php create mode 100644 src/Services/Matrix/Bridges/CapabilitiesService.php create mode 100644 src/Services/Matrix/Bridges/ContactsRawService.php create mode 100644 src/Services/Matrix/Bridges/ContactsService.php create mode 100644 src/Services/Matrix/Bridges/RoomsRawService.php create mode 100644 src/Services/Matrix/Bridges/RoomsService.php create mode 100644 src/Services/Matrix/Bridges/UsersRawService.php create mode 100644 src/Services/Matrix/Bridges/UsersService.php create mode 100644 src/Services/Matrix/BridgesRawService.php create mode 100644 src/Services/Matrix/BridgesService.php create mode 100644 src/Services/Matrix/Rooms/AccountDataRawService.php create mode 100644 src/Services/Matrix/Rooms/AccountDataService.php create mode 100644 src/Services/Matrix/Rooms/EventsRawService.php create mode 100644 src/Services/Matrix/Rooms/EventsService.php create mode 100644 src/Services/Matrix/Rooms/StateRawService.php create mode 100644 src/Services/Matrix/Rooms/StateService.php create mode 100644 src/Services/Matrix/RoomsRawService.php create mode 100644 src/Services/Matrix/RoomsService.php create mode 100644 src/Services/Matrix/Users/AccountDataRawService.php create mode 100644 src/Services/Matrix/Users/AccountDataService.php create mode 100644 src/Services/Matrix/UsersRawService.php create mode 100644 src/Services/Matrix/UsersService.php create mode 100644 src/Services/MatrixRawService.php create mode 100644 src/Services/MatrixService.php create mode 100644 tests/Services/App/E2ee/RecoveryCode/ResetTest.php create mode 100644 tests/Services/App/E2ee/RecoveryCodeTest.php create mode 100644 tests/Services/App/E2ee/Verification/QrTest.php create mode 100644 tests/Services/App/E2ee/Verification/SasTest.php create mode 100644 tests/Services/App/E2ee/VerificationTest.php create mode 100644 tests/Services/App/LoginTest.php create mode 100644 tests/Services/AppTest.php create mode 100644 tests/Services/BridgesTest.php create mode 100644 tests/Services/Matrix/Bridges/AuthTest.php create mode 100644 tests/Services/Matrix/Bridges/CapabilitiesTest.php create mode 100644 tests/Services/Matrix/Bridges/ContactsTest.php create mode 100644 tests/Services/Matrix/Bridges/RoomsTest.php create mode 100644 tests/Services/Matrix/Bridges/UsersTest.php create mode 100644 tests/Services/Matrix/Rooms/AccountDataTest.php create mode 100644 tests/Services/Matrix/Rooms/EventsTest.php create mode 100644 tests/Services/Matrix/Rooms/StateTest.php create mode 100644 tests/Services/Matrix/RoomsTest.php create mode 100644 tests/Services/Matrix/Users/AccountDataTest.php create mode 100644 tests/Services/Matrix/UsersTest.php diff --git a/.stats.yml b/.stats.yml index b85c157..b63d20d 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-371238be116b1748e82f213ba35b85b0cd574f24e9d9815f73bc743478f23c99.yml -openapi_spec_hash: a10246aaf7cdc33b682fc245bd5f893b -config_hash: 9a5611f899a0fe46abb2a1e463e0ee60 +configured_endpoints: 72 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-de1370e6a3183044fa135a886d2ee8f779d5e86228cdbd503d553b4c13cc7cbe.yml +openapi_spec_hash: 30b435d7585d8b6951610e7147369779 +config_hash: 683b13ea6fb6aa9d6b1b8814cca24f1c diff --git a/src/App/AppStatusResponse.php b/src/App/AppStatusResponse.php new file mode 100644 index 0000000..da77924 --- /dev/null +++ b/src/App/AppStatusResponse.php @@ -0,0 +1,156 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppStatusResponse implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppStatusResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppStatusResponse::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppStatusResponse)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/AppStatusResponse/E2ee.php b/src/App/AppStatusResponse/E2ee.php new file mode 100644 index 0000000..e2174da --- /dev/null +++ b/src/App/AppStatusResponse/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/AppStatusResponse/E2ee/Secrets.php b/src/App/AppStatusResponse/E2ee/Secrets.php new file mode 100644 index 0000000..cb849cb --- /dev/null +++ b/src/App/AppStatusResponse/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/AppStatusResponse/Matrix.php b/src/App/AppStatusResponse/Matrix.php new file mode 100644 index 0000000..adb49a9 --- /dev/null +++ b/src/App/AppStatusResponse/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/AppStatusResponse/State.php b/src/App/AppStatusResponse/State.php new file mode 100644 index 0000000..5317032 --- /dev/null +++ b/src/App/AppStatusResponse/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\AppStatusResponse\Verification\State|value-of<\BeeperDesktop\App\AppStatusResponse\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/AppStatusResponse/Verification/AvailableAction.php b/src/App/AppStatusResponse/Verification/AvailableAction.php new file mode 100644 index 0000000..c0d9e13 --- /dev/null +++ b/src/App/AppStatusResponse/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/AppStatusResponse/Verification/Sas.php b/src/App/AppStatusResponse/Verification/Sas.php new file mode 100644 index 0000000..84779ed --- /dev/null +++ b/src/App/AppStatusResponse/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/AppStatusResponse/Verification/State.php b/src/App/AppStatusResponse/Verification/State.php new file mode 100644 index 0000000..b4e4cee --- /dev/null +++ b/src/App/AppStatusResponse/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new RecoveryCodeMarkBackedUpResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RecoveryCodeMarkBackedUpResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RecoveryCodeMarkBackedUpResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState.php b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState.php new file mode 100644 index 0000000..6fb7fe5 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/E2ee.php b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/E2ee.php new file mode 100644 index 0000000..ab87ca1 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..088bcfe --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Matrix.php b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Matrix.php new file mode 100644 index 0000000..b838350 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/State.php b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/State.php new file mode 100644 index 0000000..f8f9f9f --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeMarkBackedUpResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeMarkBackedUpResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..67f7474 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/Sas.php b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..09d5b9e --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/State.php b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/State.php new file mode 100644 index 0000000..7d2511f --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeMarkBackedUpResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Recovery key saved by the user. + */ + #[Required] + public string $recoveryCode; + + /** + * `new RecoveryCodeVerifyParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RecoveryCodeVerifyParams::with(recoveryCode: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RecoveryCodeVerifyParams)->withRecoveryCode(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $recoveryCode): self + { + $self = new self; + + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Recovery key saved by the user. + */ + public function withRecoveryCode(string $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse.php b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse.php new file mode 100644 index 0000000..165757e --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse.php @@ -0,0 +1,77 @@ + */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new RecoveryCodeVerifyResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RecoveryCodeVerifyResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RecoveryCodeVerifyResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState.php b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState.php new file mode 100644 index 0000000..02198e9 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/E2ee.php b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/E2ee.php new file mode 100644 index 0000000..0b98e81 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..e63945e --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Matrix.php b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Matrix.php new file mode 100644 index 0000000..0511f4a --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/State.php b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/State.php new file mode 100644 index 0000000..12f3cbb --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeVerifyResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeVerifyResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..279d675 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/Sas.php b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..e528853 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/State.php b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/State.php new file mode 100644 index 0000000..47fe5d0 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/RecoveryCodeVerifyResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + use SdkParams; + + /** + * New recovery key returned by the reset step. + */ + #[Required] + public string $recoveryCode; + + /** + * `new ResetConfirmParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * ResetConfirmParams::with(recoveryCode: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new ResetConfirmParams)->withRecoveryCode(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $recoveryCode): self + { + $self = new self; + + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * New recovery key returned by the reset step. + */ + public function withRecoveryCode(string $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse.php b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse.php new file mode 100644 index 0000000..598f841 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse.php @@ -0,0 +1,77 @@ + */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new ResetConfirmResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * ResetConfirmResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new ResetConfirmResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState.php b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState.php new file mode 100644 index 0000000..acd79e9 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/E2ee.php b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/E2ee.php new file mode 100644 index 0000000..cd2714f --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..b6b86e6 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Matrix.php b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Matrix.php new file mode 100644 index 0000000..7ca6bdd --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/State.php b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/State.php new file mode 100644 index 0000000..62ded0c --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetConfirmResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetConfirmResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..856d229 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/Sas.php b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..6c87936 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/State.php b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/State.php new file mode 100644 index 0000000..4d4389c --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetConfirmResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Existing recovery key, if the user has it. + */ + #[Optional] + public ?string $recoveryCode; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $recoveryCode = null): self + { + $self = new self; + + null !== $recoveryCode && $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Existing recovery key, if the user has it. + */ + public function withRecoveryCode(string $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse.php b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse.php new file mode 100644 index 0000000..fbc6532 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse.php @@ -0,0 +1,97 @@ + */ + use SdkModel; + + /** + * Current onboarding state after creating the new recovery key. + */ + #[Required] + public AppState $appState; + + /** + * New recovery key. Show it once and ask the user to save it. + */ + #[Required] + public string $recoveryCode; + + /** + * `new ResetNewResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * ResetNewResponse::with(appState: ..., recoveryCode: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new ResetNewResponse)->withAppState(...)->withRecoveryCode(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with( + AppState|array $appState, + string $recoveryCode + ): self { + $self = new self; + + $self['appState'] = $appState; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Current onboarding state after creating the new recovery key. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } + + /** + * New recovery key. Show it once and ask the user to save it. + */ + public function withRecoveryCode(string $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState.php b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState.php new file mode 100644 index 0000000..77d0e4d --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/E2ee.php b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/E2ee.php new file mode 100644 index 0000000..8b1260e --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..ea2754a --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Matrix.php b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Matrix.php new file mode 100644 index 0000000..2a2804d --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/State.php b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/State.php new file mode 100644 index 0000000..f49916a --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetNewResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetNewResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..47ddc54 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/Sas.php b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..0d80916 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/State.php b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/State.php new file mode 100644 index 0000000..9693e80 --- /dev/null +++ b/src/App/E2ee/RecoveryCode/Reset/ResetNewResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new QrConfirmScannedResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * QrConfirmScannedResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new QrConfirmScannedResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState.php b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState.php new file mode 100644 index 0000000..6eff487 --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/E2ee.php b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/E2ee.php new file mode 100644 index 0000000..a0ec5be --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..300638b --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Matrix.php b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Matrix.php new file mode 100644 index 0000000..59f4d97 --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/State.php b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/State.php new file mode 100644 index 0000000..ec2e0da --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\Verification\Qr\QrConfirmScannedResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\Verification\Qr\QrConfirmScannedResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..7e854c9 --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/Sas.php b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..89db0e7 --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/State.php b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/State.php new file mode 100644 index 0000000..4b5cb53 --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrConfirmScannedResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + use SdkParams; + + /** + * QR code payload scanned from the other device. + */ + #[Required] + public string $data; + + /** + * `new QrScanParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * QrScanParams::with(data: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new QrScanParams)->withData(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $data): self + { + $self = new self; + + $self['data'] = $data; + + return $self; + } + + /** + * QR code payload scanned from the other device. + */ + public function withData(string $data): self + { + $self = clone $this; + $self['data'] = $data; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrScanResponse.php b/src/App/E2ee/Verification/Qr/QrScanResponse.php new file mode 100644 index 0000000..e5bfecf --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrScanResponse.php @@ -0,0 +1,75 @@ + */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new QrScanResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * QrScanResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new QrScanResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrScanResponse/AppState.php b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState.php new file mode 100644 index 0000000..2b7b76d --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/E2ee.php b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/E2ee.php new file mode 100644 index 0000000..c46c29c --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..dbc683c --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Matrix.php b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Matrix.php new file mode 100644 index 0000000..6f8390b --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/State.php b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/State.php new file mode 100644 index 0000000..3a64981 --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\Verification\Qr\QrScanResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\Verification\Qr\QrScanResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..583facb --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/Sas.php b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..3c518ac --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/State.php b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/State.php new file mode 100644 index 0000000..9c51061 --- /dev/null +++ b/src/App/E2ee/Verification/Qr/QrScanResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new SaConfirmResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * SaConfirmResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new SaConfirmResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState.php b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState.php new file mode 100644 index 0000000..54f609e --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/E2ee.php b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/E2ee.php new file mode 100644 index 0000000..3d14768 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..9805cd6 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Matrix.php b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Matrix.php new file mode 100644 index 0000000..48b1a0e --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/State.php b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/State.php new file mode 100644 index 0000000..73918e1 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\Verification\Sas\SaConfirmResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\Verification\Sas\SaConfirmResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..639296c --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/Sas.php b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..394fe95 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/State.php b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/State.php new file mode 100644 index 0000000..eb2d408 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaConfirmResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new SaStartResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * SaStartResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new SaStartResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaStartResponse/AppState.php b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState.php new file mode 100644 index 0000000..70e7073 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/E2ee.php b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/E2ee.php new file mode 100644 index 0000000..b1d6443 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..491f355 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Matrix.php b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Matrix.php new file mode 100644 index 0000000..390d3cb --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/State.php b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/State.php new file mode 100644 index 0000000..cac55c8 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\Verification\Sas\SaStartResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\Verification\Sas\SaStartResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..dea0dd1 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/Sas.php b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..d7a5284 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/State.php b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/State.php new file mode 100644 index 0000000..de4d333 --- /dev/null +++ b/src/App/E2ee/Verification/Sas/SaStartResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new VerificationAcceptResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * VerificationAcceptResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new VerificationAcceptResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationAcceptResponse/AppState.php b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState.php new file mode 100644 index 0000000..fd05c0a --- /dev/null +++ b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/E2ee.php b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/E2ee.php new file mode 100644 index 0000000..709c316 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..1fec5fc --- /dev/null +++ b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Matrix.php b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Matrix.php new file mode 100644 index 0000000..5150952 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/State.php b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/State.php new file mode 100644 index 0000000..d410d00 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\Verification\VerificationAcceptResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\Verification\VerificationAcceptResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..e2ef12c --- /dev/null +++ b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/Sas.php b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..64e0998 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/State.php b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/State.php new file mode 100644 index 0000000..312f3c5 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationAcceptResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Optional cancellation code. + */ + #[Optional] + public ?string $code; + + /** + * Optional user-facing cancellation reason. + */ + #[Optional] + public ?string $reason; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?string $code = null, + ?string $reason = null + ): self { + $self = new self; + + null !== $code && $self['code'] = $code; + null !== $reason && $self['reason'] = $reason; + + return $self; + } + + /** + * Optional cancellation code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * Optional user-facing cancellation reason. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationCancelResponse.php b/src/App/E2ee/Verification/VerificationCancelResponse.php new file mode 100644 index 0000000..54afae0 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationCancelResponse.php @@ -0,0 +1,77 @@ + */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new VerificationCancelResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * VerificationCancelResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new VerificationCancelResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationCancelResponse/AppState.php b/src/App/E2ee/Verification/VerificationCancelResponse/AppState.php new file mode 100644 index 0000000..1cad83a --- /dev/null +++ b/src/App/E2ee/Verification/VerificationCancelResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationCancelResponse/AppState/E2ee.php b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/E2ee.php new file mode 100644 index 0000000..22766e6 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationCancelResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..725667c --- /dev/null +++ b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Matrix.php b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Matrix.php new file mode 100644 index 0000000..22aa319 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationCancelResponse/AppState/State.php b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/State.php new file mode 100644 index 0000000..df4a7c9 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\Verification\VerificationCancelResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\Verification\VerificationCancelResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..3779660 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/Sas.php b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..2182246 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/State.php b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/State.php new file mode 100644 index 0000000..4059dc0 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationCancelResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + use SdkParams; + + /** + * User ID to verify. Defaults to the signed-in user. + */ + #[Optional] + public ?string $userID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $userID = null): self + { + $self = new self; + + null !== $userID && $self['userID'] = $userID; + + return $self; + } + + /** + * User ID to verify. Defaults to the signed-in user. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationNewResponse.php b/src/App/E2ee/Verification/VerificationNewResponse.php new file mode 100644 index 0000000..9b2d386 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationNewResponse.php @@ -0,0 +1,97 @@ + */ + use SdkModel; + + /** + * Current onboarding state after starting verification. + */ + #[Required] + public AppState $appState; + + /** + * Verification ID to pass in verification action paths. + */ + #[Required] + public string $verificationID; + + /** + * `new VerificationNewResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * VerificationNewResponse::with(appState: ..., verificationID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new VerificationNewResponse)->withAppState(...)->withVerificationID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with( + AppState|array $appState, + string $verificationID + ): self { + $self = new self; + + $self['appState'] = $appState; + $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Current onboarding state after starting verification. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationNewResponse/AppState.php b/src/App/E2ee/Verification/VerificationNewResponse/AppState.php new file mode 100644 index 0000000..629e61e --- /dev/null +++ b/src/App/E2ee/Verification/VerificationNewResponse/AppState.php @@ -0,0 +1,158 @@ +, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationNewResponse/AppState/E2ee.php b/src/App/E2ee/Verification/VerificationNewResponse/AppState/E2ee.php new file mode 100644 index 0000000..5f0fd04 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationNewResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationNewResponse/AppState/E2ee/Secrets.php b/src/App/E2ee/Verification/VerificationNewResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..2b9abc4 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationNewResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationNewResponse/AppState/Matrix.php b/src/App/E2ee/Verification/VerificationNewResponse/AppState/Matrix.php new file mode 100644 index 0000000..2ad248c --- /dev/null +++ b/src/App/E2ee/Verification/VerificationNewResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationNewResponse/AppState/State.php b/src/App/E2ee/Verification/VerificationNewResponse/AppState/State.php new file mode 100644 index 0000000..e8b1a5a --- /dev/null +++ b/src/App/E2ee/Verification/VerificationNewResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\E2ee\Verification\VerificationNewResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\E2ee\Verification\VerificationNewResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/AvailableAction.php b/src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..f7c067e --- /dev/null +++ b/src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/Sas.php b/src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..51ae387 --- /dev/null +++ b/src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/State.php b/src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/State.php new file mode 100644 index 0000000..cf37c8b --- /dev/null +++ b/src/App/E2ee/Verification/VerificationNewResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Email address to send the sign-in code to. + */ + #[Required] + public string $email; + + /** + * Login request ID returned by the start step. + */ + #[Required] + public string $request; + + /** + * `new LoginEmailParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * LoginEmailParams::with(email: ..., request: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new LoginEmailParams)->withEmail(...)->withRequest(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $email, string $request): self + { + $self = new self; + + $self['email'] = $email; + $self['request'] = $request; + + return $self; + } + + /** + * Email address to send the sign-in code to. + */ + public function withEmail(string $email): self + { + $self = clone $this; + $self['email'] = $email; + + return $self; + } + + /** + * Login request ID returned by the start step. + */ + public function withRequest(string $request): self + { + $self = clone $this; + $self['request'] = $request; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterParams.php b/src/App/Login/LoginRegisterParams.php new file mode 100644 index 0000000..29be2ed --- /dev/null +++ b/src/App/Login/LoginRegisterParams.php @@ -0,0 +1,140 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Confirms that the user accepted the Terms of Use and acknowledged the Privacy Policy. + */ + #[Required] + public bool $acceptTerms; + + /** + * Registration token returned by Beeper. + */ + #[Required] + public string $leadToken; + + /** + * Login request ID returned by the start step. + */ + #[Required] + public string $request; + + /** + * Username selected by the user. + */ + #[Required] + public string $username; + + /** + * `new LoginRegisterParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * LoginRegisterParams::with( + * acceptTerms: ..., leadToken: ..., request: ..., username: ... + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new LoginRegisterParams) + * ->withAcceptTerms(...) + * ->withLeadToken(...) + * ->withRequest(...) + * ->withUsername(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $acceptTerms, + string $leadToken, + string $request, + string $username + ): self { + $self = new self; + + $self['acceptTerms'] = $acceptTerms; + $self['leadToken'] = $leadToken; + $self['request'] = $request; + $self['username'] = $username; + + return $self; + } + + /** + * Confirms that the user accepted the Terms of Use and acknowledged the Privacy Policy. + */ + public function withAcceptTerms(bool $acceptTerms): self + { + $self = clone $this; + $self['acceptTerms'] = $acceptTerms; + + return $self; + } + + /** + * Registration token returned by Beeper. + */ + public function withLeadToken(string $leadToken): self + { + $self = clone $this; + $self['leadToken'] = $leadToken; + + return $self; + } + + /** + * Login request ID returned by the start step. + */ + public function withRequest(string $request): self + { + $self = clone $this; + $self['request'] = $request; + + return $self; + } + + /** + * Username selected by the user. + */ + public function withUsername(string $username): self + { + $self = clone $this; + $self['username'] = $username; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse.php b/src/App/Login/LoginRegisterResponse.php new file mode 100644 index 0000000..8d82838 --- /dev/null +++ b/src/App/Login/LoginRegisterResponse.php @@ -0,0 +1,131 @@ + */ + use SdkModel; + + /** + * Current onboarding state after sign-in. + */ + #[Required] + public AppState $appState; + + /** + * Desktop API credentials for the signed-in app session. + */ + #[Required] + public DesktopAPI $desktopAPI; + + /** + * Account credentials for first-party app setup. + */ + #[Required] + public Matrix $matrix; + + /** + * `new LoginRegisterResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * LoginRegisterResponse::with(appState: ..., desktopAPI: ..., matrix: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new LoginRegisterResponse) + * ->withAppState(...) + * ->withDesktopAPI(...) + * ->withMatrix(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + * @param DesktopAPI|DesktopAPIShape $desktopAPI + * @param Matrix|MatrixShape $matrix + */ + public static function with( + AppState|array $appState, + DesktopAPI|array $desktopAPI, + Matrix|array $matrix + ): self { + $self = new self; + + $self['appState'] = $appState; + $self['desktopAPI'] = $desktopAPI; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Current onboarding state after sign-in. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } + + /** + * Desktop API credentials for the signed-in app session. + * + * @param DesktopAPI|DesktopAPIShape $desktopAPI + */ + public function withDesktopAPI(DesktopAPI|array $desktopAPI): self + { + $self = clone $this; + $self['desktopAPI'] = $desktopAPI; + + return $self; + } + + /** + * Account credentials for first-party app setup. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse/AppState.php b/src/App/Login/LoginRegisterResponse/AppState.php new file mode 100644 index 0000000..f96b92b --- /dev/null +++ b/src/App/Login/LoginRegisterResponse/AppState.php @@ -0,0 +1,159 @@ +, + * matrix?: null|\BeeperDesktop\App\Login\LoginRegisterResponse\AppState\Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix( + Matrix|array $matrix + ): self { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse/AppState/E2ee.php b/src/App/Login/LoginRegisterResponse/AppState/E2ee.php new file mode 100644 index 0000000..2b7ecc9 --- /dev/null +++ b/src/App/Login/LoginRegisterResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse/AppState/E2ee/Secrets.php b/src/App/Login/LoginRegisterResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..ba84126 --- /dev/null +++ b/src/App/Login/LoginRegisterResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse/AppState/Matrix.php b/src/App/Login/LoginRegisterResponse/AppState/Matrix.php new file mode 100644 index 0000000..b8252b6 --- /dev/null +++ b/src/App/Login/LoginRegisterResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse/AppState/State.php b/src/App/Login/LoginRegisterResponse/AppState/State.php new file mode 100644 index 0000000..23175e8 --- /dev/null +++ b/src/App/Login/LoginRegisterResponse/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\Login\LoginRegisterResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\Login\LoginRegisterResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse/AppState/Verification/AvailableAction.php b/src/App/Login/LoginRegisterResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..89321ba --- /dev/null +++ b/src/App/Login/LoginRegisterResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse/AppState/Verification/Sas.php b/src/App/Login/LoginRegisterResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..34fa144 --- /dev/null +++ b/src/App/Login/LoginRegisterResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse/AppState/Verification/State.php b/src/App/Login/LoginRegisterResponse/AppState/Verification/State.php new file mode 100644 index 0000000..df9e05c --- /dev/null +++ b/src/App/Login/LoginRegisterResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ +, + * tokenType: TokenType|value-of, + * } + */ +final class DesktopAPI implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Desktop API access token for this app session. + */ + #[Required] + public string $accessToken; + + /** + * Granted Desktop API scopes. + * + * @var value-of $scope + */ + #[Required(enum: Scope::class)] + public string $scope; + + /** + * Access token type. + * + * @var value-of $tokenType + */ + #[Required(enum: TokenType::class)] + public string $tokenType; + + /** + * `new DesktopAPI()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * DesktopAPI::with(accessToken: ..., scope: ..., tokenType: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new DesktopAPI)->withAccessToken(...)->withScope(...)->withTokenType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Scope|value-of $scope + * @param TokenType|value-of $tokenType + */ + public static function with( + string $accessToken, + Scope|string $scope, + TokenType|string $tokenType + ): self { + $self = new self; + + $self['accessToken'] = $accessToken; + $self['scope'] = $scope; + $self['tokenType'] = $tokenType; + + return $self; + } + + /** + * Desktop API access token for this app session. + */ + public function withAccessToken(string $accessToken): self + { + $self = clone $this; + $self['accessToken'] = $accessToken; + + return $self; + } + + /** + * Granted Desktop API scopes. + * + * @param Scope|value-of $scope + */ + public function withScope(Scope|string $scope): self + { + $self = clone $this; + $self['scope'] = $scope; + + return $self; + } + + /** + * Access token type. + * + * @param TokenType|value-of $tokenType + */ + public function withTokenType(TokenType|string $tokenType): self + { + $self = clone $this; + $self['tokenType'] = $tokenType; + + return $self; + } +} diff --git a/src/App/Login/LoginRegisterResponse/DesktopAPI/Scope.php b/src/App/Login/LoginRegisterResponse/DesktopAPI/Scope.php new file mode 100644 index 0000000..9d9ea11 --- /dev/null +++ b/src/App/Login/LoginRegisterResponse/DesktopAPI/Scope.php @@ -0,0 +1,13 @@ + */ + use SdkModel; + + /** + * Account access token. Returned once for first-party app setup. + */ + #[Required] + public string $accessToken; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(accessToken: ..., deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix) + * ->withAccessToken(...) + * ->withDeviceID(...) + * ->withHomeserver(...) + * ->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $accessToken, + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['accessToken'] = $accessToken; + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Account access token. Returned once for first-party app setup. + */ + public function withAccessToken(string $accessToken): self + { + $self = clone $this; + $self['accessToken'] = $accessToken; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseParams.php b/src/App/Login/LoginResponseParams.php new file mode 100644 index 0000000..8f72a31 --- /dev/null +++ b/src/App/Login/LoginResponseParams.php @@ -0,0 +1,94 @@ + */ + use SdkModel; + use SdkParams; + + /** + * Login request ID returned by the start step. + */ + #[Required] + public string $request; + + /** + * Sign-in code from the user email. + */ + #[Required] + public string $response; + + /** + * `new LoginResponseParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * LoginResponseParams::with(request: ..., response: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new LoginResponseParams)->withRequest(...)->withResponse(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $request, string $response): self + { + $self = new self; + + $self['request'] = $request; + $self['response'] = $response; + + return $self; + } + + /** + * Login request ID returned by the start step. + */ + public function withRequest(string $request): self + { + $self = clone $this; + $self['request'] = $request; + + return $self; + } + + /** + * Sign-in code from the user email. + */ + public function withResponse(string $response): self + { + $self = clone $this; + $self['response'] = $response; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse.php b/src/App/Login/LoginResponseResponse.php new file mode 100644 index 0000000..96007f1 --- /dev/null +++ b/src/App/Login/LoginResponseResponse.php @@ -0,0 +1,31 @@ +|array + */ + public static function variants(): array + { + return [UnionMember0::class, UnionMember1::class]; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0.php b/src/App/Login/LoginResponseResponse/UnionMember0.php new file mode 100644 index 0000000..42922e2 --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0.php @@ -0,0 +1,128 @@ + */ + use SdkModel; + + /** + * Current onboarding state after sign-in. + */ + #[Required] + public AppState $appState; + + /** + * Desktop API credentials for the signed-in app session. + */ + #[Required] + public DesktopAPI $desktopAPI; + + /** + * Account credentials for first-party app setup. + */ + #[Required] + public Matrix $matrix; + + /** + * `new UnionMember0()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember0::with(appState: ..., desktopAPI: ..., matrix: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember0)->withAppState(...)->withDesktopAPI(...)->withMatrix(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + * @param DesktopAPI|DesktopAPIShape $desktopAPI + * @param Matrix|MatrixShape $matrix + */ + public static function with( + AppState|array $appState, + DesktopAPI|array $desktopAPI, + Matrix|array $matrix + ): self { + $self = new self; + + $self['appState'] = $appState; + $self['desktopAPI'] = $desktopAPI; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Current onboarding state after sign-in. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } + + /** + * Desktop API credentials for the signed-in app session. + * + * @param DesktopAPI|DesktopAPIShape $desktopAPI + */ + public function withDesktopAPI(DesktopAPI|array $desktopAPI): self + { + $self = clone $this; + $self['desktopAPI'] = $desktopAPI; + + return $self; + } + + /** + * Account credentials for first-party app setup. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0/AppState.php b/src/App/Login/LoginResponseResponse/UnionMember0/AppState.php new file mode 100644 index 0000000..aca97ab --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0/AppState.php @@ -0,0 +1,159 @@ +, + * matrix?: null|\BeeperDesktop\App\Login\LoginResponseResponse\UnionMember0\AppState\Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix( + Matrix|array $matrix, + ): self { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0/AppState/E2ee.php b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/E2ee.php new file mode 100644 index 0000000..fd66739 --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/E2ee.php @@ -0,0 +1,260 @@ + */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0/AppState/E2ee/Secrets.php b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..c8a2e19 --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ + */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Matrix.php b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Matrix.php new file mode 100644 index 0000000..f12fb12 --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Matrix.php @@ -0,0 +1,111 @@ + */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0/AppState/State.php b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/State.php new file mode 100644 index 0000000..8c4580c --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/State.php @@ -0,0 +1,25 @@ +>, + * state: \BeeperDesktop\App\Login\LoginResponseResponse\UnionMember0\AppState\Verification\State|value-of<\BeeperDesktop\App\Login\LoginResponseResponse\UnionMember0\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list> $availableActions + * @param State|value-of $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/AvailableAction.php b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..3074006 --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ + */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/Sas.php b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/Sas.php new file mode 100644 index 0000000..0125e95 --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ + */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/State.php b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/State.php new file mode 100644 index 0000000..d5ef8ae --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0/AppState/Verification/State.php @@ -0,0 +1,27 @@ +, + * tokenType: TokenType|value-of, + * } + */ +final class DesktopAPI implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Desktop API access token for this app session. + */ + #[Required] + public string $accessToken; + + /** + * Granted Desktop API scopes. + * + * @var value-of $scope + */ + #[Required(enum: Scope::class)] + public string $scope; + + /** + * Access token type. + * + * @var value-of $tokenType + */ + #[Required(enum: TokenType::class)] + public string $tokenType; + + /** + * `new DesktopAPI()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * DesktopAPI::with(accessToken: ..., scope: ..., tokenType: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new DesktopAPI)->withAccessToken(...)->withScope(...)->withTokenType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Scope|value-of $scope + * @param TokenType|value-of $tokenType + */ + public static function with( + string $accessToken, + Scope|string $scope, + TokenType|string $tokenType + ): self { + $self = new self; + + $self['accessToken'] = $accessToken; + $self['scope'] = $scope; + $self['tokenType'] = $tokenType; + + return $self; + } + + /** + * Desktop API access token for this app session. + */ + public function withAccessToken(string $accessToken): self + { + $self = clone $this; + $self['accessToken'] = $accessToken; + + return $self; + } + + /** + * Granted Desktop API scopes. + * + * @param Scope|value-of $scope + */ + public function withScope(Scope|string $scope): self + { + $self = clone $this; + $self['scope'] = $scope; + + return $self; + } + + /** + * Access token type. + * + * @param TokenType|value-of $tokenType + */ + public function withTokenType(TokenType|string $tokenType): self + { + $self = clone $this; + $self['tokenType'] = $tokenType; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember0/DesktopAPI/Scope.php b/src/App/Login/LoginResponseResponse/UnionMember0/DesktopAPI/Scope.php new file mode 100644 index 0000000..2c6cd84 --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember0/DesktopAPI/Scope.php @@ -0,0 +1,13 @@ + */ + use SdkModel; + + /** + * Account access token. Returned once for first-party app setup. + */ + #[Required] + public string $accessToken; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(accessToken: ..., deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix) + * ->withAccessToken(...) + * ->withDeviceID(...) + * ->withHomeserver(...) + * ->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $accessToken, + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['accessToken'] = $accessToken; + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Account access token. Returned once for first-party app setup. + */ + public function withAccessToken(string $accessToken): self + { + $self = clone $this; + $self['accessToken'] = $accessToken; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember1.php b/src/App/Login/LoginResponseResponse/UnionMember1.php new file mode 100644 index 0000000..4639305 --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember1.php @@ -0,0 +1,171 @@ +|null, + * } + */ +final class UnionMember1 implements BaseModel +{ + /** @use SdkModel */ + use SdkModel; + + /** + * Copy to display during account creation. + */ + #[Required] + public Copy $copy; + + /** + * Registration token returned by Beeper. + */ + #[Required] + public string $leadToken; + + /** + * Indicates that the user needs to create a Beeper account. + */ + #[Required] + public bool $registrationRequired; + + /** + * Login request ID to use when creating the account. + */ + #[Required] + public string $request; + + /** + * Suggested usernames for the new account. + * + * @var list|null $usernameSuggestions + */ + #[Optional(list: 'string')] + public ?array $usernameSuggestions; + + /** + * `new UnionMember1()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember1::with( + * copy: ..., leadToken: ..., registrationRequired: ..., request: ... + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember1) + * ->withCopy(...) + * ->withLeadToken(...) + * ->withRegistrationRequired(...) + * ->withRequest(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Copy|CopyShape $copy + * @param list|null $usernameSuggestions + */ + public static function with( + Copy|array $copy, + string $leadToken, + bool $registrationRequired, + string $request, + ?array $usernameSuggestions = null, + ): self { + $self = new self; + + $self['copy'] = $copy; + $self['leadToken'] = $leadToken; + $self['registrationRequired'] = $registrationRequired; + $self['request'] = $request; + + null !== $usernameSuggestions && $self['usernameSuggestions'] = $usernameSuggestions; + + return $self; + } + + /** + * Copy to display during account creation. + * + * @param Copy|CopyShape $copy + */ + public function withCopy(Copy|array $copy): self + { + $self = clone $this; + $self['copy'] = $copy; + + return $self; + } + + /** + * Registration token returned by Beeper. + */ + public function withLeadToken(string $leadToken): self + { + $self = clone $this; + $self['leadToken'] = $leadToken; + + return $self; + } + + /** + * Indicates that the user needs to create a Beeper account. + */ + public function withRegistrationRequired(bool $registrationRequired): self + { + $self = clone $this; + $self['registrationRequired'] = $registrationRequired; + + return $self; + } + + /** + * Login request ID to use when creating the account. + */ + public function withRequest(string $request): self + { + $self = clone $this; + $self['request'] = $request; + + return $self; + } + + /** + * Suggested usernames for the new account. + * + * @param list $usernameSuggestions + */ + public function withUsernameSuggestions(array $usernameSuggestions): self + { + $self = clone $this; + $self['usernameSuggestions'] = $usernameSuggestions; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember1/Copy.php b/src/App/Login/LoginResponseResponse/UnionMember1/Copy.php new file mode 100644 index 0000000..51f10dd --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember1/Copy.php @@ -0,0 +1,163 @@ +, + * terms: Terms|value-of, + * title: Title|value-of, + * usernamePlaceholder: UsernamePlaceholder|value-of<UsernamePlaceholder>, + * } + */ +final class Copy implements BaseModel +{ + /** @use SdkModel<CopyShape> */ + use SdkModel; + + /** + * Submit button label. + * + * @var value-of<Submit> $submit + */ + #[Required(enum: Submit::class)] + public string $submit; + + /** + * Terms and privacy notice to show before account creation. + * + * @var value-of<Terms> $terms + */ + #[Required(enum: Terms::class)] + public string $terms; + + /** + * Title for the username step. + * + * @var value-of<Title> $title + */ + #[Required(enum: Title::class)] + public string $title; + + /** + * Placeholder for the username field. + * + * @var value-of<UsernamePlaceholder> $usernamePlaceholder + */ + #[Required(enum: UsernamePlaceholder::class)] + public string $usernamePlaceholder; + + /** + * `new Copy()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Copy::with(submit: ..., terms: ..., title: ..., usernamePlaceholder: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Copy) + * ->withSubmit(...) + * ->withTerms(...) + * ->withTitle(...) + * ->withUsernamePlaceholder(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Submit|value-of<Submit> $submit + * @param Terms|value-of<Terms> $terms + * @param Title|value-of<Title> $title + * @param UsernamePlaceholder|value-of<UsernamePlaceholder> $usernamePlaceholder + */ + public static function with( + Submit|string $submit, + Terms|string $terms, + Title|string $title, + UsernamePlaceholder|string $usernamePlaceholder, + ): self { + $self = new self; + + $self['submit'] = $submit; + $self['terms'] = $terms; + $self['title'] = $title; + $self['usernamePlaceholder'] = $usernamePlaceholder; + + return $self; + } + + /** + * Submit button label. + * + * @param Submit|value-of<Submit> $submit + */ + public function withSubmit(Submit|string $submit): self + { + $self = clone $this; + $self['submit'] = $submit; + + return $self; + } + + /** + * Terms and privacy notice to show before account creation. + * + * @param Terms|value-of<Terms> $terms + */ + public function withTerms(Terms|string $terms): self + { + $self = clone $this; + $self['terms'] = $terms; + + return $self; + } + + /** + * Title for the username step. + * + * @param Title|value-of<Title> $title + */ + public function withTitle(Title|string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } + + /** + * Placeholder for the username field. + * + * @param UsernamePlaceholder|value-of<UsernamePlaceholder> $usernamePlaceholder + */ + public function withUsernamePlaceholder( + UsernamePlaceholder|string $usernamePlaceholder + ): self { + $self = clone $this; + $self['usernamePlaceholder'] = $usernamePlaceholder; + + return $self; + } +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember1/Copy/Submit.php b/src/App/Login/LoginResponseResponse/UnionMember1/Copy/Submit.php new file mode 100644 index 0000000..c789afa --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember1/Copy/Submit.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\Login\LoginResponseResponse\UnionMember1\Copy; + +/** + * Submit button label. + */ +enum Submit: string +{ + case CONTINUE = 'Continue'; +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember1/Copy/Terms.php b/src/App/Login/LoginResponseResponse/UnionMember1/Copy/Terms.php new file mode 100644 index 0000000..7bc655e --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember1/Copy/Terms.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\Login\LoginResponseResponse\UnionMember1\Copy; + +/** + * Terms and privacy notice to show before account creation. + */ +enum Terms: string +{ + case BY_CONTINUING_YOU_AGREE_TO_THE_TERMS_OF_USE_AND_ACKNOWLEDGE_THE_PRIVACY_POLICY = 'By continuing, you agree to the Terms of Use and acknowledge the Privacy Policy.'; +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember1/Copy/Title.php b/src/App/Login/LoginResponseResponse/UnionMember1/Copy/Title.php new file mode 100644 index 0000000..391cb30 --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember1/Copy/Title.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\Login\LoginResponseResponse\UnionMember1\Copy; + +/** + * Title for the username step. + */ +enum Title: string +{ + case CHOOSE_YOUR_USERNAME = 'Choose your username'; +} diff --git a/src/App/Login/LoginResponseResponse/UnionMember1/Copy/UsernamePlaceholder.php b/src/App/Login/LoginResponseResponse/UnionMember1/Copy/UsernamePlaceholder.php new file mode 100644 index 0000000..602c90e --- /dev/null +++ b/src/App/Login/LoginResponseResponse/UnionMember1/Copy/UsernamePlaceholder.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\Login\LoginResponseResponse\UnionMember1\Copy; + +/** + * Placeholder for the username field. + */ +enum UsernamePlaceholder: string +{ + case USERNAME = 'Username'; +} diff --git a/src/App/Login/LoginStartResponse.php b/src/App/Login/LoginStartResponse.php new file mode 100644 index 0000000..f7664c9 --- /dev/null +++ b/src/App/Login/LoginStartResponse.php @@ -0,0 +1,94 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\Login; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-type LoginStartResponseShape = array{ + * request: string, type: list<string> + * } + */ +final class LoginStartResponse implements BaseModel +{ + /** @use SdkModel<LoginStartResponseShape> */ + use SdkModel; + + /** + * Login request ID to use in the next sign-in step. + */ + #[Required] + public string $request; + + /** + * Available sign-in methods for this request. + * + * @var list<string> $type + */ + #[Required(list: 'string')] + public array $type; + + /** + * `new LoginStartResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * LoginStartResponse::with(request: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new LoginStartResponse)->withRequest(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<string> $type + */ + public static function with(string $request, array $type): self + { + $self = new self; + + $self['request'] = $request; + $self['type'] = $type; + + return $self; + } + + /** + * Login request ID to use in the next sign-in step. + */ + public function withRequest(string $request): self + { + $self = clone $this; + $self['request'] = $request; + + return $self; + } + + /** + * Available sign-in methods for this request. + * + * @param list<string> $type + */ + public function withType(array $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } +} diff --git a/src/App/LoginRegistrationRequiredResponse.php b/src/App/LoginRegistrationRequiredResponse.php new file mode 100644 index 0000000..c417c05 --- /dev/null +++ b/src/App/LoginRegistrationRequiredResponse.php @@ -0,0 +1,171 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App; + +use BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-import-type CopyShape from \BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy + * + * @phpstan-type LoginRegistrationRequiredResponseShape = array{ + * copy: Copy|CopyShape, + * leadToken: string, + * registrationRequired: bool, + * request: string, + * usernameSuggestions?: list<string>|null, + * } + */ +final class LoginRegistrationRequiredResponse implements BaseModel +{ + /** @use SdkModel<LoginRegistrationRequiredResponseShape> */ + use SdkModel; + + /** + * Copy to display during account creation. + */ + #[Required] + public Copy $copy; + + /** + * Registration token returned by Beeper. + */ + #[Required] + public string $leadToken; + + /** + * Indicates that the user needs to create a Beeper account. + */ + #[Required] + public bool $registrationRequired; + + /** + * Login request ID to use when creating the account. + */ + #[Required] + public string $request; + + /** + * Suggested usernames for the new account. + * + * @var list<string>|null $usernameSuggestions + */ + #[Optional(list: 'string')] + public ?array $usernameSuggestions; + + /** + * `new LoginRegistrationRequiredResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * LoginRegistrationRequiredResponse::with( + * copy: ..., leadToken: ..., registrationRequired: ..., request: ... + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new LoginRegistrationRequiredResponse) + * ->withCopy(...) + * ->withLeadToken(...) + * ->withRegistrationRequired(...) + * ->withRequest(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Copy|CopyShape $copy + * @param list<string>|null $usernameSuggestions + */ + public static function with( + Copy|array $copy, + string $leadToken, + bool $registrationRequired, + string $request, + ?array $usernameSuggestions = null, + ): self { + $self = new self; + + $self['copy'] = $copy; + $self['leadToken'] = $leadToken; + $self['registrationRequired'] = $registrationRequired; + $self['request'] = $request; + + null !== $usernameSuggestions && $self['usernameSuggestions'] = $usernameSuggestions; + + return $self; + } + + /** + * Copy to display during account creation. + * + * @param Copy|CopyShape $copy + */ + public function withCopy(Copy|array $copy): self + { + $self = clone $this; + $self['copy'] = $copy; + + return $self; + } + + /** + * Registration token returned by Beeper. + */ + public function withLeadToken(string $leadToken): self + { + $self = clone $this; + $self['leadToken'] = $leadToken; + + return $self; + } + + /** + * Indicates that the user needs to create a Beeper account. + */ + public function withRegistrationRequired(bool $registrationRequired): self + { + $self = clone $this; + $self['registrationRequired'] = $registrationRequired; + + return $self; + } + + /** + * Login request ID to use when creating the account. + */ + public function withRequest(string $request): self + { + $self = clone $this; + $self['request'] = $request; + + return $self; + } + + /** + * Suggested usernames for the new account. + * + * @param list<string> $usernameSuggestions + */ + public function withUsernameSuggestions(array $usernameSuggestions): self + { + $self = clone $this; + $self['usernameSuggestions'] = $usernameSuggestions; + + return $self; + } +} diff --git a/src/App/LoginRegistrationRequiredResponse/Copy.php b/src/App/LoginRegistrationRequiredResponse/Copy.php new file mode 100644 index 0000000..c74dfc8 --- /dev/null +++ b/src/App/LoginRegistrationRequiredResponse/Copy.php @@ -0,0 +1,163 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginRegistrationRequiredResponse; + +use BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy\Submit; +use BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy\Terms; +use BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy\Title; +use BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy\UsernamePlaceholder; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Copy to display during account creation. + * + * @phpstan-type CopyShape = array{ + * submit: Submit|value-of<Submit>, + * terms: Terms|value-of<Terms>, + * title: Title|value-of<Title>, + * usernamePlaceholder: UsernamePlaceholder|value-of<UsernamePlaceholder>, + * } + */ +final class Copy implements BaseModel +{ + /** @use SdkModel<CopyShape> */ + use SdkModel; + + /** + * Submit button label. + * + * @var value-of<Submit> $submit + */ + #[Required(enum: Submit::class)] + public string $submit; + + /** + * Terms and privacy notice to show before account creation. + * + * @var value-of<Terms> $terms + */ + #[Required(enum: Terms::class)] + public string $terms; + + /** + * Title for the username step. + * + * @var value-of<Title> $title + */ + #[Required(enum: Title::class)] + public string $title; + + /** + * Placeholder for the username field. + * + * @var value-of<UsernamePlaceholder> $usernamePlaceholder + */ + #[Required(enum: UsernamePlaceholder::class)] + public string $usernamePlaceholder; + + /** + * `new Copy()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Copy::with(submit: ..., terms: ..., title: ..., usernamePlaceholder: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Copy) + * ->withSubmit(...) + * ->withTerms(...) + * ->withTitle(...) + * ->withUsernamePlaceholder(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Submit|value-of<Submit> $submit + * @param Terms|value-of<Terms> $terms + * @param Title|value-of<Title> $title + * @param UsernamePlaceholder|value-of<UsernamePlaceholder> $usernamePlaceholder + */ + public static function with( + Submit|string $submit, + Terms|string $terms, + Title|string $title, + UsernamePlaceholder|string $usernamePlaceholder, + ): self { + $self = new self; + + $self['submit'] = $submit; + $self['terms'] = $terms; + $self['title'] = $title; + $self['usernamePlaceholder'] = $usernamePlaceholder; + + return $self; + } + + /** + * Submit button label. + * + * @param Submit|value-of<Submit> $submit + */ + public function withSubmit(Submit|string $submit): self + { + $self = clone $this; + $self['submit'] = $submit; + + return $self; + } + + /** + * Terms and privacy notice to show before account creation. + * + * @param Terms|value-of<Terms> $terms + */ + public function withTerms(Terms|string $terms): self + { + $self = clone $this; + $self['terms'] = $terms; + + return $self; + } + + /** + * Title for the username step. + * + * @param Title|value-of<Title> $title + */ + public function withTitle(Title|string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } + + /** + * Placeholder for the username field. + * + * @param UsernamePlaceholder|value-of<UsernamePlaceholder> $usernamePlaceholder + */ + public function withUsernamePlaceholder( + UsernamePlaceholder|string $usernamePlaceholder + ): self { + $self = clone $this; + $self['usernamePlaceholder'] = $usernamePlaceholder; + + return $self; + } +} diff --git a/src/App/LoginRegistrationRequiredResponse/Copy/Submit.php b/src/App/LoginRegistrationRequiredResponse/Copy/Submit.php new file mode 100644 index 0000000..9d8abd8 --- /dev/null +++ b/src/App/LoginRegistrationRequiredResponse/Copy/Submit.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy; + +/** + * Submit button label. + */ +enum Submit: string +{ + case CONTINUE = 'Continue'; +} diff --git a/src/App/LoginRegistrationRequiredResponse/Copy/Terms.php b/src/App/LoginRegistrationRequiredResponse/Copy/Terms.php new file mode 100644 index 0000000..f662980 --- /dev/null +++ b/src/App/LoginRegistrationRequiredResponse/Copy/Terms.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy; + +/** + * Terms and privacy notice to show before account creation. + */ +enum Terms: string +{ + case BY_CONTINUING_YOU_AGREE_TO_THE_TERMS_OF_USE_AND_ACKNOWLEDGE_THE_PRIVACY_POLICY = 'By continuing, you agree to the Terms of Use and acknowledge the Privacy Policy.'; +} diff --git a/src/App/LoginRegistrationRequiredResponse/Copy/Title.php b/src/App/LoginRegistrationRequiredResponse/Copy/Title.php new file mode 100644 index 0000000..85ef00a --- /dev/null +++ b/src/App/LoginRegistrationRequiredResponse/Copy/Title.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy; + +/** + * Title for the username step. + */ +enum Title: string +{ + case CHOOSE_YOUR_USERNAME = 'Choose your username'; +} diff --git a/src/App/LoginRegistrationRequiredResponse/Copy/UsernamePlaceholder.php b/src/App/LoginRegistrationRequiredResponse/Copy/UsernamePlaceholder.php new file mode 100644 index 0000000..675fb56 --- /dev/null +++ b/src/App/LoginRegistrationRequiredResponse/Copy/UsernamePlaceholder.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginRegistrationRequiredResponse\Copy; + +/** + * Placeholder for the username field. + */ +enum UsernamePlaceholder: string +{ + case USERNAME = 'Username'; +} diff --git a/src/App/LoginResponse.php b/src/App/LoginResponse.php new file mode 100644 index 0000000..86923d4 --- /dev/null +++ b/src/App/LoginResponse.php @@ -0,0 +1,128 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App; + +use BeeperDesktop\App\LoginResponse\AppState; +use BeeperDesktop\App\LoginResponse\DesktopAPI; +use BeeperDesktop\App\LoginResponse\Matrix; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-import-type AppStateShape from \BeeperDesktop\App\LoginResponse\AppState + * @phpstan-import-type DesktopAPIShape from \BeeperDesktop\App\LoginResponse\DesktopAPI + * @phpstan-import-type MatrixShape from \BeeperDesktop\App\LoginResponse\Matrix + * + * @phpstan-type LoginResponseShape = array{ + * appState: AppState|AppStateShape, + * desktopAPI: DesktopAPI|DesktopAPIShape, + * matrix: Matrix|MatrixShape, + * } + */ +final class LoginResponse implements BaseModel +{ + /** @use SdkModel<LoginResponseShape> */ + use SdkModel; + + /** + * Current onboarding state after sign-in. + */ + #[Required] + public AppState $appState; + + /** + * Desktop API credentials for the signed-in app session. + */ + #[Required] + public DesktopAPI $desktopAPI; + + /** + * Account credentials for first-party app setup. + */ + #[Required] + public Matrix $matrix; + + /** + * `new LoginResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * LoginResponse::with(appState: ..., desktopAPI: ..., matrix: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new LoginResponse)->withAppState(...)->withDesktopAPI(...)->withMatrix(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + * @param DesktopAPI|DesktopAPIShape $desktopAPI + * @param Matrix|MatrixShape $matrix + */ + public static function with( + AppState|array $appState, + DesktopAPI|array $desktopAPI, + Matrix|array $matrix + ): self { + $self = new self; + + $self['appState'] = $appState; + $self['desktopAPI'] = $desktopAPI; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Current onboarding state after sign-in. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } + + /** + * Desktop API credentials for the signed-in app session. + * + * @param DesktopAPI|DesktopAPIShape $desktopAPI + */ + public function withDesktopAPI(DesktopAPI|array $desktopAPI): self + { + $self = clone $this; + $self['desktopAPI'] = $desktopAPI; + + return $self; + } + + /** + * Account credentials for first-party app setup. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } +} diff --git a/src/App/LoginResponse/AppState.php b/src/App/LoginResponse/AppState.php new file mode 100644 index 0000000..95a1612 --- /dev/null +++ b/src/App/LoginResponse/AppState.php @@ -0,0 +1,159 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse; + +use BeeperDesktop\App\LoginResponse\AppState\E2ee; +use BeeperDesktop\App\LoginResponse\AppState\Matrix; +use BeeperDesktop\App\LoginResponse\AppState\State; +use BeeperDesktop\App\LoginResponse\AppState\Verification; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Current onboarding state after sign-in. + * + * @phpstan-import-type E2eeShape from \BeeperDesktop\App\LoginResponse\AppState\E2ee + * @phpstan-import-type MatrixShape from \BeeperDesktop\App\LoginResponse\AppState\Matrix + * @phpstan-import-type VerificationShape from \BeeperDesktop\App\LoginResponse\AppState\Verification + * + * @phpstan-type AppStateShape = array{ + * e2ee: E2ee|E2eeShape, + * state: State|value-of<State>, + * matrix?: null|\BeeperDesktop\App\LoginResponse\AppState\Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel<AppStateShape> */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of<State> $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of<State> $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of<State> $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix( + Matrix|array $matrix + ): self { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/LoginResponse/AppState/E2ee.php b/src/App/LoginResponse/AppState/E2ee.php new file mode 100644 index 0000000..12900fd --- /dev/null +++ b/src/App/LoginResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\AppState; + +use BeeperDesktop\App\LoginResponse\AppState\E2ee\Secrets; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging setup status. + * + * @phpstan-import-type SecretsShape from \BeeperDesktop\App\LoginResponse\AppState\E2ee\Secrets + * + * @phpstan-type E2eeShape = array{ + * crossSigning: bool, + * firstSyncDone: bool, + * hasBackedUpCode: bool, + * initialized: bool, + * keyBackup: bool, + * secrets: Secrets|SecretsShape, + * secretStorage: bool, + * verified: bool, + * recoveryCodeGeneratedAt?: float|null, + * } + */ +final class E2ee implements BaseModel +{ + /** @use SdkModel<E2eeShape> */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/LoginResponse/AppState/E2ee/Secrets.php b/src/App/LoginResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..ba5d856 --- /dev/null +++ b/src/App/LoginResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\AppState\E2ee; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging keys available on this device. + * + * @phpstan-type SecretsShape = array{ + * masterKey: bool, + * megolmBackupKey: bool, + * recoveryCode: bool, + * selfSigningKey: bool, + * userSigningKey: bool, + * } + */ +final class Secrets implements BaseModel +{ + /** @use SdkModel<SecretsShape> */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/LoginResponse/AppState/Matrix.php b/src/App/LoginResponse/AppState/Matrix.php new file mode 100644 index 0000000..abf44b9 --- /dev/null +++ b/src/App/LoginResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\AppState; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Signed-in account details. Omitted until sign-in is complete. + * + * @phpstan-type MatrixShape = array{ + * deviceID: string, homeserver: string, userID: string + * } + */ +final class Matrix implements BaseModel +{ + /** @use SdkModel<MatrixShape> */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/LoginResponse/AppState/State.php b/src/App/LoginResponse/AppState/State.php new file mode 100644 index 0000000..f9dcbe1 --- /dev/null +++ b/src/App/LoginResponse/AppState/State.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\AppState; + +/** + * Current onboarding state for Beeper Desktop. + */ +enum State: string +{ + case NEEDS_LOGIN = 'needs-login'; + + case INITIALIZING = 'initializing'; + + case NEEDS_CROSS_SIGNING_SETUP = 'needs-cross-signing-setup'; + + case NEEDS_VERIFICATION = 'needs-verification'; + + case NEEDS_SECRETS = 'needs-secrets'; + + case NEEDS_FIRST_SYNC = 'needs-first-sync'; + + case READY = 'ready'; +} diff --git a/src/App/LoginResponse/AppState/Verification.php b/src/App/LoginResponse/AppState/Verification.php new file mode 100644 index 0000000..d8119e6 --- /dev/null +++ b/src/App/LoginResponse/AppState/Verification.php @@ -0,0 +1,302 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\AppState; + +use BeeperDesktop\App\LoginResponse\AppState\Verification\AvailableAction; +use BeeperDesktop\App\LoginResponse\AppState\Verification\Error; +use BeeperDesktop\App\LoginResponse\AppState\Verification\Sas; +use BeeperDesktop\App\LoginResponse\AppState\Verification\State; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Trusted-device verification progress. + * + * @phpstan-import-type ErrorShape from \BeeperDesktop\App\LoginResponse\AppState\Verification\Error + * @phpstan-import-type SasShape from \BeeperDesktop\App\LoginResponse\AppState\Verification\Sas + * + * @phpstan-type VerificationShape = array{ + * availableActions: list<AvailableAction|value-of<AvailableAction>>, + * state: \BeeperDesktop\App\LoginResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\LoginResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel<VerificationShape> */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list<value-of<AvailableAction>> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of<State> $state + */ + #[Required( + enum: State::class + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + * @param State|value-of<State> $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of<State> $state + */ + public function withState( + State|string $state + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/LoginResponse/AppState/Verification/AvailableAction.php b/src/App/LoginResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..582e770 --- /dev/null +++ b/src/App/LoginResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\AppState\Verification; + +enum AvailableAction: string +{ + case CREATE = 'create'; + + case QR_SCAN = 'qr.scan'; + + case ACCEPT = 'accept'; + + case CANCEL = 'cancel'; + + case QR_CONFIRM_SCANNED = 'qr.confirmScanned'; + + case SAS_START = 'sas.start'; + + case SAS_CONFIRM = 'sas.confirm'; +} diff --git a/src/App/LoginResponse/AppState/Verification/Error.php b/src/App/LoginResponse/AppState/Verification/Error.php new file mode 100644 index 0000000..80b26ed --- /dev/null +++ b/src/App/LoginResponse/AppState/Verification/Error.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Verification error details, if verification stopped. + * + * @phpstan-type ErrorShape = array{code: string, reason: string} + */ +final class Error implements BaseModel +{ + /** @use SdkModel<ErrorShape> */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/LoginResponse/AppState/Verification/Sas.php b/src/App/LoginResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..496be03 --- /dev/null +++ b/src/App/LoginResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Emoji or number comparison data for verification. + * + * @phpstan-type SasShape = array{decimals: string, emojis: string} + */ +final class Sas implements BaseModel +{ + /** @use SdkModel<SasShape> */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/LoginResponse/AppState/Verification/State.php b/src/App/LoginResponse/AppState/Verification/State.php new file mode 100644 index 0000000..43fb7cc --- /dev/null +++ b/src/App/LoginResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\AppState\Verification; + +/** + * Current trusted-device verification state. + */ +enum State: string +{ + case IDLE = 'idle'; + + case REQUESTED = 'requested'; + + case READY = 'ready'; + + case SAS_READY = 'sas_ready'; + + case QR_SCANNED = 'qr_scanned'; + + case DONE = 'done'; + + case CANCELLED = 'cancelled'; + + case ERROR = 'error'; +} diff --git a/src/App/LoginResponse/DesktopAPI.php b/src/App/LoginResponse/DesktopAPI.php new file mode 100644 index 0000000..60575fd --- /dev/null +++ b/src/App/LoginResponse/DesktopAPI.php @@ -0,0 +1,126 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse; + +use BeeperDesktop\App\LoginResponse\DesktopAPI\Scope; +use BeeperDesktop\App\LoginResponse\DesktopAPI\TokenType; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Desktop API credentials for the signed-in app session. + * + * @phpstan-type DesktopAPIShape = array{ + * accessToken: string, + * scope: Scope|value-of<Scope>, + * tokenType: TokenType|value-of<TokenType>, + * } + */ +final class DesktopAPI implements BaseModel +{ + /** @use SdkModel<DesktopAPIShape> */ + use SdkModel; + + /** + * Desktop API access token for this app session. + */ + #[Required] + public string $accessToken; + + /** + * Granted Desktop API scopes. + * + * @var value-of<Scope> $scope + */ + #[Required(enum: Scope::class)] + public string $scope; + + /** + * Access token type. + * + * @var value-of<TokenType> $tokenType + */ + #[Required(enum: TokenType::class)] + public string $tokenType; + + /** + * `new DesktopAPI()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * DesktopAPI::with(accessToken: ..., scope: ..., tokenType: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new DesktopAPI)->withAccessToken(...)->withScope(...)->withTokenType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Scope|value-of<Scope> $scope + * @param TokenType|value-of<TokenType> $tokenType + */ + public static function with( + string $accessToken, + Scope|string $scope, + TokenType|string $tokenType + ): self { + $self = new self; + + $self['accessToken'] = $accessToken; + $self['scope'] = $scope; + $self['tokenType'] = $tokenType; + + return $self; + } + + /** + * Desktop API access token for this app session. + */ + public function withAccessToken(string $accessToken): self + { + $self = clone $this; + $self['accessToken'] = $accessToken; + + return $self; + } + + /** + * Granted Desktop API scopes. + * + * @param Scope|value-of<Scope> $scope + */ + public function withScope(Scope|string $scope): self + { + $self = clone $this; + $self['scope'] = $scope; + + return $self; + } + + /** + * Access token type. + * + * @param TokenType|value-of<TokenType> $tokenType + */ + public function withTokenType(TokenType|string $tokenType): self + { + $self = clone $this; + $self['tokenType'] = $tokenType; + + return $self; + } +} diff --git a/src/App/LoginResponse/DesktopAPI/Scope.php b/src/App/LoginResponse/DesktopAPI/Scope.php new file mode 100644 index 0000000..a55ba18 --- /dev/null +++ b/src/App/LoginResponse/DesktopAPI/Scope.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\DesktopAPI; + +/** + * Granted Desktop API scopes. + */ +enum Scope: string +{ + case READ_WRITE = 'read write'; +} diff --git a/src/App/LoginResponse/DesktopAPI/TokenType.php b/src/App/LoginResponse/DesktopAPI/TokenType.php new file mode 100644 index 0000000..0d7f9c3 --- /dev/null +++ b/src/App/LoginResponse/DesktopAPI/TokenType.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse\DesktopAPI; + +/** + * Access token type. + */ +enum TokenType: string +{ + case BEARER = 'Bearer'; +} diff --git a/src/App/LoginResponse/Matrix.php b/src/App/LoginResponse/Matrix.php new file mode 100644 index 0000000..a3bdb94 --- /dev/null +++ b/src/App/LoginResponse/Matrix.php @@ -0,0 +1,134 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponse; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Account credentials for first-party app setup. + * + * @phpstan-type MatrixShape = array{ + * accessToken: string, deviceID: string, homeserver: string, userID: string + * } + */ +final class Matrix implements BaseModel +{ + /** @use SdkModel<MatrixShape> */ + use SdkModel; + + /** + * Account access token. Returned once for first-party app setup. + */ + #[Required] + public string $accessToken; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(accessToken: ..., deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix) + * ->withAccessToken(...) + * ->withDeviceID(...) + * ->withHomeserver(...) + * ->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $accessToken, + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['accessToken'] = $accessToken; + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Account access token. Returned once for first-party app setup. + */ + public function withAccessToken(string $accessToken): self + { + $self = clone $this; + $self['accessToken'] = $accessToken; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput.php b/src/App/LoginResponseOutput.php new file mode 100644 index 0000000..41912db --- /dev/null +++ b/src/App/LoginResponseOutput.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App; + +use BeeperDesktop\App\LoginResponseOutput\UnionMember0; +use BeeperDesktop\App\LoginResponseOutput\UnionMember1; +use BeeperDesktop\Core\Concerns\SdkUnion; +use BeeperDesktop\Core\Conversion\Contracts\Converter; +use BeeperDesktop\Core\Conversion\Contracts\ConverterSource; + +/** + * @phpstan-import-type UnionMember0Shape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0 + * @phpstan-import-type UnionMember1Shape from \BeeperDesktop\App\LoginResponseOutput\UnionMember1 + * + * @phpstan-type LoginResponseOutputVariants = UnionMember0|UnionMember1 + * @phpstan-type LoginResponseOutputShape = LoginResponseOutputVariants|UnionMember0Shape|UnionMember1Shape + */ +final class LoginResponseOutput implements ConverterSource +{ + use SdkUnion; + + /** + * @return list<string|Converter|ConverterSource>|array<string,string|Converter|ConverterSource> + */ + public static function variants(): array + { + return [UnionMember0::class, UnionMember1::class]; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0.php b/src/App/LoginResponseOutput/UnionMember0.php new file mode 100644 index 0000000..fd2949f --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0.php @@ -0,0 +1,128 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput; + +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState; +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\DesktopAPI; +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\Matrix; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-import-type AppStateShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState + * @phpstan-import-type DesktopAPIShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0\DesktopAPI + * @phpstan-import-type MatrixShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0\Matrix + * + * @phpstan-type UnionMember0Shape = array{ + * appState: AppState|AppStateShape, + * desktopAPI: DesktopAPI|DesktopAPIShape, + * matrix: Matrix|MatrixShape, + * } + */ +final class UnionMember0 implements BaseModel +{ + /** @use SdkModel<UnionMember0Shape> */ + use SdkModel; + + /** + * Current onboarding state after sign-in. + */ + #[Required] + public AppState $appState; + + /** + * Desktop API credentials for the signed-in app session. + */ + #[Required] + public DesktopAPI $desktopAPI; + + /** + * Account credentials for first-party app setup. + */ + #[Required] + public Matrix $matrix; + + /** + * `new UnionMember0()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember0::with(appState: ..., desktopAPI: ..., matrix: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember0)->withAppState(...)->withDesktopAPI(...)->withMatrix(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + * @param DesktopAPI|DesktopAPIShape $desktopAPI + * @param Matrix|MatrixShape $matrix + */ + public static function with( + AppState|array $appState, + DesktopAPI|array $desktopAPI, + Matrix|array $matrix + ): self { + $self = new self; + + $self['appState'] = $appState; + $self['desktopAPI'] = $desktopAPI; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Current onboarding state after sign-in. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } + + /** + * Desktop API credentials for the signed-in app session. + * + * @param DesktopAPI|DesktopAPIShape $desktopAPI + */ + public function withDesktopAPI(DesktopAPI|array $desktopAPI): self + { + $self = clone $this; + $self['desktopAPI'] = $desktopAPI; + + return $self; + } + + /** + * Account credentials for first-party app setup. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState.php b/src/App/LoginResponseOutput/UnionMember0/AppState.php new file mode 100644 index 0000000..258211d --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState.php @@ -0,0 +1,159 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0; + +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\E2ee; +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Matrix; +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\State; +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Current onboarding state after sign-in. + * + * @phpstan-import-type E2eeShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\E2ee + * @phpstan-import-type MatrixShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Matrix + * @phpstan-import-type VerificationShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification + * + * @phpstan-type AppStateShape = array{ + * e2ee: E2ee|E2eeShape, + * state: State|value-of<State>, + * matrix?: null|\BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel<AppStateShape> */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of<State> $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of<State> $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of<State> $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix( + Matrix|array $matrix, + ): self { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState/E2ee.php b/src/App/LoginResponseOutput/UnionMember0/AppState/E2ee.php new file mode 100644 index 0000000..4d33613 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState/E2ee.php @@ -0,0 +1,260 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState; + +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\E2ee\Secrets; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging setup status. + * + * @phpstan-import-type SecretsShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\E2ee\Secrets + * + * @phpstan-type E2eeShape = array{ + * crossSigning: bool, + * firstSyncDone: bool, + * hasBackedUpCode: bool, + * initialized: bool, + * keyBackup: bool, + * secrets: Secrets|SecretsShape, + * secretStorage: bool, + * verified: bool, + * recoveryCodeGeneratedAt?: float|null, + * } + */ +final class E2ee implements BaseModel +{ + /** @use SdkModel<E2eeShape> */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState/E2ee/Secrets.php b/src/App/LoginResponseOutput/UnionMember0/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..2c75e32 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\E2ee; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging keys available on this device. + * + * @phpstan-type SecretsShape = array{ + * masterKey: bool, + * megolmBackupKey: bool, + * recoveryCode: bool, + * selfSigningKey: bool, + * userSigningKey: bool, + * } + */ +final class Secrets implements BaseModel +{ + /** @use SdkModel<SecretsShape> */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState/Matrix.php b/src/App/LoginResponseOutput/UnionMember0/AppState/Matrix.php new file mode 100644 index 0000000..2d61209 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState/Matrix.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Signed-in account details. Omitted until sign-in is complete. + * + * @phpstan-type MatrixShape = array{ + * deviceID: string, homeserver: string, userID: string + * } + */ +final class Matrix implements BaseModel +{ + /** @use SdkModel<MatrixShape> */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState/State.php b/src/App/LoginResponseOutput/UnionMember0/AppState/State.php new file mode 100644 index 0000000..40d5c08 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState/State.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState; + +/** + * Current onboarding state for Beeper Desktop. + */ +enum State: string +{ + case NEEDS_LOGIN = 'needs-login'; + + case INITIALIZING = 'initializing'; + + case NEEDS_CROSS_SIGNING_SETUP = 'needs-cross-signing-setup'; + + case NEEDS_VERIFICATION = 'needs-verification'; + + case NEEDS_SECRETS = 'needs-secrets'; + + case NEEDS_FIRST_SYNC = 'needs-first-sync'; + + case READY = 'ready'; +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState/Verification.php b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification.php new file mode 100644 index 0000000..79e88d9 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification.php @@ -0,0 +1,302 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState; + +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification\AvailableAction; +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification\Error; +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification\Sas; +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification\State; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Trusted-device verification progress. + * + * @phpstan-import-type ErrorShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification\Error + * @phpstan-import-type SasShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification\Sas + * + * @phpstan-type VerificationShape = array{ + * availableActions: list<AvailableAction|value-of<AvailableAction>>, + * state: \BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification\State|value-of<\BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel<VerificationShape> */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list<value-of<AvailableAction>> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of<State> $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + * @param State|value-of<State> $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of<State> $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/AvailableAction.php b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..1dc722f --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification; + +enum AvailableAction: string +{ + case CREATE = 'create'; + + case QR_SCAN = 'qr.scan'; + + case ACCEPT = 'accept'; + + case CANCEL = 'cancel'; + + case QR_CONFIRM_SCANNED = 'qr.confirmScanned'; + + case SAS_START = 'sas.start'; + + case SAS_CONFIRM = 'sas.confirm'; +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/Error.php b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/Error.php new file mode 100644 index 0000000..1fec2ee --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/Error.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Verification error details, if verification stopped. + * + * @phpstan-type ErrorShape = array{code: string, reason: string} + */ +final class Error implements BaseModel +{ + /** @use SdkModel<ErrorShape> */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/Sas.php b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/Sas.php new file mode 100644 index 0000000..353b73c --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Emoji or number comparison data for verification. + * + * @phpstan-type SasShape = array{decimals: string, emojis: string} + */ +final class Sas implements BaseModel +{ + /** @use SdkModel<SasShape> */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/State.php b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/State.php new file mode 100644 index 0000000..f3ff31c --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/AppState/Verification/State.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\AppState\Verification; + +/** + * Current trusted-device verification state. + */ +enum State: string +{ + case IDLE = 'idle'; + + case REQUESTED = 'requested'; + + case READY = 'ready'; + + case SAS_READY = 'sas_ready'; + + case QR_SCANNED = 'qr_scanned'; + + case DONE = 'done'; + + case CANCELLED = 'cancelled'; + + case ERROR = 'error'; +} diff --git a/src/App/LoginResponseOutput/UnionMember0/DesktopAPI.php b/src/App/LoginResponseOutput/UnionMember0/DesktopAPI.php new file mode 100644 index 0000000..42ad2a4 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/DesktopAPI.php @@ -0,0 +1,126 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0; + +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\DesktopAPI\Scope; +use BeeperDesktop\App\LoginResponseOutput\UnionMember0\DesktopAPI\TokenType; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Desktop API credentials for the signed-in app session. + * + * @phpstan-type DesktopAPIShape = array{ + * accessToken: string, + * scope: Scope|value-of<Scope>, + * tokenType: TokenType|value-of<TokenType>, + * } + */ +final class DesktopAPI implements BaseModel +{ + /** @use SdkModel<DesktopAPIShape> */ + use SdkModel; + + /** + * Desktop API access token for this app session. + */ + #[Required] + public string $accessToken; + + /** + * Granted Desktop API scopes. + * + * @var value-of<Scope> $scope + */ + #[Required(enum: Scope::class)] + public string $scope; + + /** + * Access token type. + * + * @var value-of<TokenType> $tokenType + */ + #[Required(enum: TokenType::class)] + public string $tokenType; + + /** + * `new DesktopAPI()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * DesktopAPI::with(accessToken: ..., scope: ..., tokenType: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new DesktopAPI)->withAccessToken(...)->withScope(...)->withTokenType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Scope|value-of<Scope> $scope + * @param TokenType|value-of<TokenType> $tokenType + */ + public static function with( + string $accessToken, + Scope|string $scope, + TokenType|string $tokenType + ): self { + $self = new self; + + $self['accessToken'] = $accessToken; + $self['scope'] = $scope; + $self['tokenType'] = $tokenType; + + return $self; + } + + /** + * Desktop API access token for this app session. + */ + public function withAccessToken(string $accessToken): self + { + $self = clone $this; + $self['accessToken'] = $accessToken; + + return $self; + } + + /** + * Granted Desktop API scopes. + * + * @param Scope|value-of<Scope> $scope + */ + public function withScope(Scope|string $scope): self + { + $self = clone $this; + $self['scope'] = $scope; + + return $self; + } + + /** + * Access token type. + * + * @param TokenType|value-of<TokenType> $tokenType + */ + public function withTokenType(TokenType|string $tokenType): self + { + $self = clone $this; + $self['tokenType'] = $tokenType; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember0/DesktopAPI/Scope.php b/src/App/LoginResponseOutput/UnionMember0/DesktopAPI/Scope.php new file mode 100644 index 0000000..210c0c1 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/DesktopAPI/Scope.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\DesktopAPI; + +/** + * Granted Desktop API scopes. + */ +enum Scope: string +{ + case READ_WRITE = 'read write'; +} diff --git a/src/App/LoginResponseOutput/UnionMember0/DesktopAPI/TokenType.php b/src/App/LoginResponseOutput/UnionMember0/DesktopAPI/TokenType.php new file mode 100644 index 0000000..5dd5411 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/DesktopAPI/TokenType.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0\DesktopAPI; + +/** + * Access token type. + */ +enum TokenType: string +{ + case BEARER = 'Bearer'; +} diff --git a/src/App/LoginResponseOutput/UnionMember0/Matrix.php b/src/App/LoginResponseOutput/UnionMember0/Matrix.php new file mode 100644 index 0000000..03f1859 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember0/Matrix.php @@ -0,0 +1,134 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember0; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Account credentials for first-party app setup. + * + * @phpstan-type MatrixShape = array{ + * accessToken: string, deviceID: string, homeserver: string, userID: string + * } + */ +final class Matrix implements BaseModel +{ + /** @use SdkModel<MatrixShape> */ + use SdkModel; + + /** + * Account access token. Returned once for first-party app setup. + */ + #[Required] + public string $accessToken; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(accessToken: ..., deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix) + * ->withAccessToken(...) + * ->withDeviceID(...) + * ->withHomeserver(...) + * ->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $accessToken, + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['accessToken'] = $accessToken; + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Account access token. Returned once for first-party app setup. + */ + public function withAccessToken(string $accessToken): self + { + $self = clone $this; + $self['accessToken'] = $accessToken; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember1.php b/src/App/LoginResponseOutput/UnionMember1.php new file mode 100644 index 0000000..ffec2b5 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember1.php @@ -0,0 +1,171 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput; + +use BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-import-type CopyShape from \BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy + * + * @phpstan-type UnionMember1Shape = array{ + * copy: Copy|CopyShape, + * leadToken: string, + * registrationRequired: bool, + * request: string, + * usernameSuggestions?: list<string>|null, + * } + */ +final class UnionMember1 implements BaseModel +{ + /** @use SdkModel<UnionMember1Shape> */ + use SdkModel; + + /** + * Copy to display during account creation. + */ + #[Required] + public Copy $copy; + + /** + * Registration token returned by Beeper. + */ + #[Required] + public string $leadToken; + + /** + * Indicates that the user needs to create a Beeper account. + */ + #[Required] + public bool $registrationRequired; + + /** + * Login request ID to use when creating the account. + */ + #[Required] + public string $request; + + /** + * Suggested usernames for the new account. + * + * @var list<string>|null $usernameSuggestions + */ + #[Optional(list: 'string')] + public ?array $usernameSuggestions; + + /** + * `new UnionMember1()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember1::with( + * copy: ..., leadToken: ..., registrationRequired: ..., request: ... + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember1) + * ->withCopy(...) + * ->withLeadToken(...) + * ->withRegistrationRequired(...) + * ->withRequest(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Copy|CopyShape $copy + * @param list<string>|null $usernameSuggestions + */ + public static function with( + Copy|array $copy, + string $leadToken, + bool $registrationRequired, + string $request, + ?array $usernameSuggestions = null, + ): self { + $self = new self; + + $self['copy'] = $copy; + $self['leadToken'] = $leadToken; + $self['registrationRequired'] = $registrationRequired; + $self['request'] = $request; + + null !== $usernameSuggestions && $self['usernameSuggestions'] = $usernameSuggestions; + + return $self; + } + + /** + * Copy to display during account creation. + * + * @param Copy|CopyShape $copy + */ + public function withCopy(Copy|array $copy): self + { + $self = clone $this; + $self['copy'] = $copy; + + return $self; + } + + /** + * Registration token returned by Beeper. + */ + public function withLeadToken(string $leadToken): self + { + $self = clone $this; + $self['leadToken'] = $leadToken; + + return $self; + } + + /** + * Indicates that the user needs to create a Beeper account. + */ + public function withRegistrationRequired(bool $registrationRequired): self + { + $self = clone $this; + $self['registrationRequired'] = $registrationRequired; + + return $self; + } + + /** + * Login request ID to use when creating the account. + */ + public function withRequest(string $request): self + { + $self = clone $this; + $self['request'] = $request; + + return $self; + } + + /** + * Suggested usernames for the new account. + * + * @param list<string> $usernameSuggestions + */ + public function withUsernameSuggestions(array $usernameSuggestions): self + { + $self = clone $this; + $self['usernameSuggestions'] = $usernameSuggestions; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember1/Copy.php b/src/App/LoginResponseOutput/UnionMember1/Copy.php new file mode 100644 index 0000000..0f1b345 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember1/Copy.php @@ -0,0 +1,163 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember1; + +use BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy\Submit; +use BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy\Terms; +use BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy\Title; +use BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy\UsernamePlaceholder; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Copy to display during account creation. + * + * @phpstan-type CopyShape = array{ + * submit: Submit|value-of<Submit>, + * terms: Terms|value-of<Terms>, + * title: Title|value-of<Title>, + * usernamePlaceholder: UsernamePlaceholder|value-of<UsernamePlaceholder>, + * } + */ +final class Copy implements BaseModel +{ + /** @use SdkModel<CopyShape> */ + use SdkModel; + + /** + * Submit button label. + * + * @var value-of<Submit> $submit + */ + #[Required(enum: Submit::class)] + public string $submit; + + /** + * Terms and privacy notice to show before account creation. + * + * @var value-of<Terms> $terms + */ + #[Required(enum: Terms::class)] + public string $terms; + + /** + * Title for the username step. + * + * @var value-of<Title> $title + */ + #[Required(enum: Title::class)] + public string $title; + + /** + * Placeholder for the username field. + * + * @var value-of<UsernamePlaceholder> $usernamePlaceholder + */ + #[Required(enum: UsernamePlaceholder::class)] + public string $usernamePlaceholder; + + /** + * `new Copy()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Copy::with(submit: ..., terms: ..., title: ..., usernamePlaceholder: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Copy) + * ->withSubmit(...) + * ->withTerms(...) + * ->withTitle(...) + * ->withUsernamePlaceholder(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Submit|value-of<Submit> $submit + * @param Terms|value-of<Terms> $terms + * @param Title|value-of<Title> $title + * @param UsernamePlaceholder|value-of<UsernamePlaceholder> $usernamePlaceholder + */ + public static function with( + Submit|string $submit, + Terms|string $terms, + Title|string $title, + UsernamePlaceholder|string $usernamePlaceholder, + ): self { + $self = new self; + + $self['submit'] = $submit; + $self['terms'] = $terms; + $self['title'] = $title; + $self['usernamePlaceholder'] = $usernamePlaceholder; + + return $self; + } + + /** + * Submit button label. + * + * @param Submit|value-of<Submit> $submit + */ + public function withSubmit(Submit|string $submit): self + { + $self = clone $this; + $self['submit'] = $submit; + + return $self; + } + + /** + * Terms and privacy notice to show before account creation. + * + * @param Terms|value-of<Terms> $terms + */ + public function withTerms(Terms|string $terms): self + { + $self = clone $this; + $self['terms'] = $terms; + + return $self; + } + + /** + * Title for the username step. + * + * @param Title|value-of<Title> $title + */ + public function withTitle(Title|string $title): self + { + $self = clone $this; + $self['title'] = $title; + + return $self; + } + + /** + * Placeholder for the username field. + * + * @param UsernamePlaceholder|value-of<UsernamePlaceholder> $usernamePlaceholder + */ + public function withUsernamePlaceholder( + UsernamePlaceholder|string $usernamePlaceholder + ): self { + $self = clone $this; + $self['usernamePlaceholder'] = $usernamePlaceholder; + + return $self; + } +} diff --git a/src/App/LoginResponseOutput/UnionMember1/Copy/Submit.php b/src/App/LoginResponseOutput/UnionMember1/Copy/Submit.php new file mode 100644 index 0000000..d4087c0 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember1/Copy/Submit.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy; + +/** + * Submit button label. + */ +enum Submit: string +{ + case CONTINUE = 'Continue'; +} diff --git a/src/App/LoginResponseOutput/UnionMember1/Copy/Terms.php b/src/App/LoginResponseOutput/UnionMember1/Copy/Terms.php new file mode 100644 index 0000000..f187fa7 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember1/Copy/Terms.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy; + +/** + * Terms and privacy notice to show before account creation. + */ +enum Terms: string +{ + case BY_CONTINUING_YOU_AGREE_TO_THE_TERMS_OF_USE_AND_ACKNOWLEDGE_THE_PRIVACY_POLICY = 'By continuing, you agree to the Terms of Use and acknowledge the Privacy Policy.'; +} diff --git a/src/App/LoginResponseOutput/UnionMember1/Copy/Title.php b/src/App/LoginResponseOutput/UnionMember1/Copy/Title.php new file mode 100644 index 0000000..0956696 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember1/Copy/Title.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy; + +/** + * Title for the username step. + */ +enum Title: string +{ + case CHOOSE_YOUR_USERNAME = 'Choose your username'; +} diff --git a/src/App/LoginResponseOutput/UnionMember1/Copy/UsernamePlaceholder.php b/src/App/LoginResponseOutput/UnionMember1/Copy/UsernamePlaceholder.php new file mode 100644 index 0000000..10332c5 --- /dev/null +++ b/src/App/LoginResponseOutput/UnionMember1/Copy/UsernamePlaceholder.php @@ -0,0 +1,13 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\LoginResponseOutput\UnionMember1\Copy; + +/** + * Placeholder for the username field. + */ +enum UsernamePlaceholder: string +{ + case USERNAME = 'Username'; +} diff --git a/src/App/RecoveryCodeResetResponse.php b/src/App/RecoveryCodeResetResponse.php new file mode 100644 index 0000000..9eb6a30 --- /dev/null +++ b/src/App/RecoveryCodeResetResponse.php @@ -0,0 +1,97 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App; + +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-import-type AppStateShape from \BeeperDesktop\App\RecoveryCodeResetResponse\AppState + * + * @phpstan-type RecoveryCodeResetResponseShape = array{ + * appState: AppState|AppStateShape, recoveryCode: string + * } + */ +final class RecoveryCodeResetResponse implements BaseModel +{ + /** @use SdkModel<RecoveryCodeResetResponseShape> */ + use SdkModel; + + /** + * Current onboarding state after creating the new recovery key. + */ + #[Required] + public AppState $appState; + + /** + * New recovery key. Show it once and ask the user to save it. + */ + #[Required] + public string $recoveryCode; + + /** + * `new RecoveryCodeResetResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RecoveryCodeResetResponse::with(appState: ..., recoveryCode: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RecoveryCodeResetResponse)->withAppState(...)->withRecoveryCode(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with( + AppState|array $appState, + string $recoveryCode + ): self { + $self = new self; + + $self['appState'] = $appState; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Current onboarding state after creating the new recovery key. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } + + /** + * New recovery key. Show it once and ask the user to save it. + */ + public function withRecoveryCode(string $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } +} diff --git a/src/App/RecoveryCodeResetResponse/AppState.php b/src/App/RecoveryCodeResetResponse/AppState.php new file mode 100644 index 0000000..5179338 --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse; + +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState\E2ee; +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Matrix; +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState\State; +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Current onboarding state after creating the new recovery key. + * + * @phpstan-import-type E2eeShape from \BeeperDesktop\App\RecoveryCodeResetResponse\AppState\E2ee + * @phpstan-import-type MatrixShape from \BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Matrix + * @phpstan-import-type VerificationShape from \BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification + * + * @phpstan-type AppStateShape = array{ + * e2ee: E2ee|E2eeShape, + * state: State|value-of<State>, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel<AppStateShape> */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of<State> $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of<State> $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of<State> $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/RecoveryCodeResetResponse/AppState/E2ee.php b/src/App/RecoveryCodeResetResponse/AppState/E2ee.php new file mode 100644 index 0000000..2947c90 --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse\AppState; + +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState\E2ee\Secrets; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging setup status. + * + * @phpstan-import-type SecretsShape from \BeeperDesktop\App\RecoveryCodeResetResponse\AppState\E2ee\Secrets + * + * @phpstan-type E2eeShape = array{ + * crossSigning: bool, + * firstSyncDone: bool, + * hasBackedUpCode: bool, + * initialized: bool, + * keyBackup: bool, + * secrets: Secrets|SecretsShape, + * secretStorage: bool, + * verified: bool, + * recoveryCodeGeneratedAt?: float|null, + * } + */ +final class E2ee implements BaseModel +{ + /** @use SdkModel<E2eeShape> */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/RecoveryCodeResetResponse/AppState/E2ee/Secrets.php b/src/App/RecoveryCodeResetResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..b126517 --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse\AppState\E2ee; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging keys available on this device. + * + * @phpstan-type SecretsShape = array{ + * masterKey: bool, + * megolmBackupKey: bool, + * recoveryCode: bool, + * selfSigningKey: bool, + * userSigningKey: bool, + * } + */ +final class Secrets implements BaseModel +{ + /** @use SdkModel<SecretsShape> */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/RecoveryCodeResetResponse/AppState/Matrix.php b/src/App/RecoveryCodeResetResponse/AppState/Matrix.php new file mode 100644 index 0000000..d8e5d38 --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse\AppState; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Signed-in account details. Omitted until sign-in is complete. + * + * @phpstan-type MatrixShape = array{ + * deviceID: string, homeserver: string, userID: string + * } + */ +final class Matrix implements BaseModel +{ + /** @use SdkModel<MatrixShape> */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/RecoveryCodeResetResponse/AppState/State.php b/src/App/RecoveryCodeResetResponse/AppState/State.php new file mode 100644 index 0000000..6cecf9f --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState/State.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse\AppState; + +/** + * Current onboarding state for Beeper Desktop. + */ +enum State: string +{ + case NEEDS_LOGIN = 'needs-login'; + + case INITIALIZING = 'initializing'; + + case NEEDS_CROSS_SIGNING_SETUP = 'needs-cross-signing-setup'; + + case NEEDS_VERIFICATION = 'needs-verification'; + + case NEEDS_SECRETS = 'needs-secrets'; + + case NEEDS_FIRST_SYNC = 'needs-first-sync'; + + case READY = 'ready'; +} diff --git a/src/App/RecoveryCodeResetResponse/AppState/Verification.php b/src/App/RecoveryCodeResetResponse/AppState/Verification.php new file mode 100644 index 0000000..556ce42 --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState/Verification.php @@ -0,0 +1,302 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse\AppState; + +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification\AvailableAction; +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification\Error; +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification\Sas; +use BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification\State; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Trusted-device verification progress. + * + * @phpstan-import-type ErrorShape from \BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification\Error + * @phpstan-import-type SasShape from \BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification\Sas + * + * @phpstan-type VerificationShape = array{ + * availableActions: list<AvailableAction|value-of<AvailableAction>>, + * state: \BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel<VerificationShape> */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list<value-of<AvailableAction>> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of<State> $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + * @param State|value-of<State> $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of<State> $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/RecoveryCodeResetResponse/AppState/Verification/AvailableAction.php b/src/App/RecoveryCodeResetResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..d7b0da4 --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification; + +enum AvailableAction: string +{ + case CREATE = 'create'; + + case QR_SCAN = 'qr.scan'; + + case ACCEPT = 'accept'; + + case CANCEL = 'cancel'; + + case QR_CONFIRM_SCANNED = 'qr.confirmScanned'; + + case SAS_START = 'sas.start'; + + case SAS_CONFIRM = 'sas.confirm'; +} diff --git a/src/App/RecoveryCodeResetResponse/AppState/Verification/Error.php b/src/App/RecoveryCodeResetResponse/AppState/Verification/Error.php new file mode 100644 index 0000000..b22d98b --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState/Verification/Error.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Verification error details, if verification stopped. + * + * @phpstan-type ErrorShape = array{code: string, reason: string} + */ +final class Error implements BaseModel +{ + /** @use SdkModel<ErrorShape> */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/RecoveryCodeResetResponse/AppState/Verification/Sas.php b/src/App/RecoveryCodeResetResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..114ec2c --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Emoji or number comparison data for verification. + * + * @phpstan-type SasShape = array{decimals: string, emojis: string} + */ +final class Sas implements BaseModel +{ + /** @use SdkModel<SasShape> */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/RecoveryCodeResetResponse/AppState/Verification/State.php b/src/App/RecoveryCodeResetResponse/AppState/Verification/State.php new file mode 100644 index 0000000..9f7ca42 --- /dev/null +++ b/src/App/RecoveryCodeResetResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\RecoveryCodeResetResponse\AppState\Verification; + +/** + * Current trusted-device verification state. + */ +enum State: string +{ + case IDLE = 'idle'; + + case REQUESTED = 'requested'; + + case READY = 'ready'; + + case SAS_READY = 'sas_ready'; + + case QR_SCANNED = 'qr_scanned'; + + case DONE = 'done'; + + case CANCELLED = 'cancelled'; + + case ERROR = 'error'; +} diff --git a/src/App/StartVerificationResponse.php b/src/App/StartVerificationResponse.php new file mode 100644 index 0000000..53e9f21 --- /dev/null +++ b/src/App/StartVerificationResponse.php @@ -0,0 +1,97 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App; + +use BeeperDesktop\App\StartVerificationResponse\AppState; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-import-type AppStateShape from \BeeperDesktop\App\StartVerificationResponse\AppState + * + * @phpstan-type StartVerificationResponseShape = array{ + * appState: AppState|AppStateShape, verificationID: string + * } + */ +final class StartVerificationResponse implements BaseModel +{ + /** @use SdkModel<StartVerificationResponseShape> */ + use SdkModel; + + /** + * Current onboarding state after starting verification. + */ + #[Required] + public AppState $appState; + + /** + * Verification ID to pass in verification action paths. + */ + #[Required] + public string $verificationID; + + /** + * `new StartVerificationResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * StartVerificationResponse::with(appState: ..., verificationID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new StartVerificationResponse)->withAppState(...)->withVerificationID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with( + AppState|array $appState, + string $verificationID + ): self { + $self = new self; + + $self['appState'] = $appState; + $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Current onboarding state after starting verification. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/StartVerificationResponse/AppState.php b/src/App/StartVerificationResponse/AppState.php new file mode 100644 index 0000000..4304f7a --- /dev/null +++ b/src/App/StartVerificationResponse/AppState.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse; + +use BeeperDesktop\App\StartVerificationResponse\AppState\E2ee; +use BeeperDesktop\App\StartVerificationResponse\AppState\Matrix; +use BeeperDesktop\App\StartVerificationResponse\AppState\State; +use BeeperDesktop\App\StartVerificationResponse\AppState\Verification; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Current onboarding state after starting verification. + * + * @phpstan-import-type E2eeShape from \BeeperDesktop\App\StartVerificationResponse\AppState\E2ee + * @phpstan-import-type MatrixShape from \BeeperDesktop\App\StartVerificationResponse\AppState\Matrix + * @phpstan-import-type VerificationShape from \BeeperDesktop\App\StartVerificationResponse\AppState\Verification + * + * @phpstan-type AppStateShape = array{ + * e2ee: E2ee|E2eeShape, + * state: State|value-of<State>, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel<AppStateShape> */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of<State> $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of<State> $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of<State> $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/StartVerificationResponse/AppState/E2ee.php b/src/App/StartVerificationResponse/AppState/E2ee.php new file mode 100644 index 0000000..953d4c9 --- /dev/null +++ b/src/App/StartVerificationResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse\AppState; + +use BeeperDesktop\App\StartVerificationResponse\AppState\E2ee\Secrets; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging setup status. + * + * @phpstan-import-type SecretsShape from \BeeperDesktop\App\StartVerificationResponse\AppState\E2ee\Secrets + * + * @phpstan-type E2eeShape = array{ + * crossSigning: bool, + * firstSyncDone: bool, + * hasBackedUpCode: bool, + * initialized: bool, + * keyBackup: bool, + * secrets: Secrets|SecretsShape, + * secretStorage: bool, + * verified: bool, + * recoveryCodeGeneratedAt?: float|null, + * } + */ +final class E2ee implements BaseModel +{ + /** @use SdkModel<E2eeShape> */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/StartVerificationResponse/AppState/E2ee/Secrets.php b/src/App/StartVerificationResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..97d5f07 --- /dev/null +++ b/src/App/StartVerificationResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse\AppState\E2ee; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging keys available on this device. + * + * @phpstan-type SecretsShape = array{ + * masterKey: bool, + * megolmBackupKey: bool, + * recoveryCode: bool, + * selfSigningKey: bool, + * userSigningKey: bool, + * } + */ +final class Secrets implements BaseModel +{ + /** @use SdkModel<SecretsShape> */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/StartVerificationResponse/AppState/Matrix.php b/src/App/StartVerificationResponse/AppState/Matrix.php new file mode 100644 index 0000000..ba79a32 --- /dev/null +++ b/src/App/StartVerificationResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse\AppState; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Signed-in account details. Omitted until sign-in is complete. + * + * @phpstan-type MatrixShape = array{ + * deviceID: string, homeserver: string, userID: string + * } + */ +final class Matrix implements BaseModel +{ + /** @use SdkModel<MatrixShape> */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/StartVerificationResponse/AppState/State.php b/src/App/StartVerificationResponse/AppState/State.php new file mode 100644 index 0000000..bf54994 --- /dev/null +++ b/src/App/StartVerificationResponse/AppState/State.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse\AppState; + +/** + * Current onboarding state for Beeper Desktop. + */ +enum State: string +{ + case NEEDS_LOGIN = 'needs-login'; + + case INITIALIZING = 'initializing'; + + case NEEDS_CROSS_SIGNING_SETUP = 'needs-cross-signing-setup'; + + case NEEDS_VERIFICATION = 'needs-verification'; + + case NEEDS_SECRETS = 'needs-secrets'; + + case NEEDS_FIRST_SYNC = 'needs-first-sync'; + + case READY = 'ready'; +} diff --git a/src/App/StartVerificationResponse/AppState/Verification.php b/src/App/StartVerificationResponse/AppState/Verification.php new file mode 100644 index 0000000..9026a92 --- /dev/null +++ b/src/App/StartVerificationResponse/AppState/Verification.php @@ -0,0 +1,302 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse\AppState; + +use BeeperDesktop\App\StartVerificationResponse\AppState\Verification\AvailableAction; +use BeeperDesktop\App\StartVerificationResponse\AppState\Verification\Error; +use BeeperDesktop\App\StartVerificationResponse\AppState\Verification\Sas; +use BeeperDesktop\App\StartVerificationResponse\AppState\Verification\State; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Trusted-device verification progress. + * + * @phpstan-import-type ErrorShape from \BeeperDesktop\App\StartVerificationResponse\AppState\Verification\Error + * @phpstan-import-type SasShape from \BeeperDesktop\App\StartVerificationResponse\AppState\Verification\Sas + * + * @phpstan-type VerificationShape = array{ + * availableActions: list<AvailableAction|value-of<AvailableAction>>, + * state: \BeeperDesktop\App\StartVerificationResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\StartVerificationResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel<VerificationShape> */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list<value-of<AvailableAction>> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of<State> $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + * @param State|value-of<State> $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of<State> $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/StartVerificationResponse/AppState/Verification/AvailableAction.php b/src/App/StartVerificationResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..be0aa82 --- /dev/null +++ b/src/App/StartVerificationResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse\AppState\Verification; + +enum AvailableAction: string +{ + case CREATE = 'create'; + + case QR_SCAN = 'qr.scan'; + + case ACCEPT = 'accept'; + + case CANCEL = 'cancel'; + + case QR_CONFIRM_SCANNED = 'qr.confirmScanned'; + + case SAS_START = 'sas.start'; + + case SAS_CONFIRM = 'sas.confirm'; +} diff --git a/src/App/StartVerificationResponse/AppState/Verification/Error.php b/src/App/StartVerificationResponse/AppState/Verification/Error.php new file mode 100644 index 0000000..03200ca --- /dev/null +++ b/src/App/StartVerificationResponse/AppState/Verification/Error.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Verification error details, if verification stopped. + * + * @phpstan-type ErrorShape = array{code: string, reason: string} + */ +final class Error implements BaseModel +{ + /** @use SdkModel<ErrorShape> */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/StartVerificationResponse/AppState/Verification/Sas.php b/src/App/StartVerificationResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..e86c5ac --- /dev/null +++ b/src/App/StartVerificationResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Emoji or number comparison data for verification. + * + * @phpstan-type SasShape = array{decimals: string, emojis: string} + */ +final class Sas implements BaseModel +{ + /** @use SdkModel<SasShape> */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/StartVerificationResponse/AppState/Verification/State.php b/src/App/StartVerificationResponse/AppState/Verification/State.php new file mode 100644 index 0000000..5ebb496 --- /dev/null +++ b/src/App/StartVerificationResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StartVerificationResponse\AppState\Verification; + +/** + * Current trusted-device verification state. + */ +enum State: string +{ + case IDLE = 'idle'; + + case REQUESTED = 'requested'; + + case READY = 'ready'; + + case SAS_READY = 'sas_ready'; + + case QR_SCANNED = 'qr_scanned'; + + case DONE = 'done'; + + case CANCELLED = 'cancelled'; + + case ERROR = 'error'; +} diff --git a/src/App/StateMutationResponse.php b/src/App/StateMutationResponse.php new file mode 100644 index 0000000..39b638d --- /dev/null +++ b/src/App/StateMutationResponse.php @@ -0,0 +1,77 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App; + +use BeeperDesktop\App\StateMutationResponse\AppState; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-import-type AppStateShape from \BeeperDesktop\App\StateMutationResponse\AppState + * + * @phpstan-type StateMutationResponseShape = array{ + * appState: AppState|AppStateShape + * } + */ +final class StateMutationResponse implements BaseModel +{ + /** @use SdkModel<StateMutationResponseShape> */ + use SdkModel; + + /** + * Current onboarding state after the requested step. + */ + #[Required] + public AppState $appState; + + /** + * `new StateMutationResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * StateMutationResponse::with(appState: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new StateMutationResponse)->withAppState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param AppState|AppStateShape $appState + */ + public static function with(AppState|array $appState): self + { + $self = new self; + + $self['appState'] = $appState; + + return $self; + } + + /** + * Current onboarding state after the requested step. + * + * @param AppState|AppStateShape $appState + */ + public function withAppState(AppState|array $appState): self + { + $self = clone $this; + $self['appState'] = $appState; + + return $self; + } +} diff --git a/src/App/StateMutationResponse/AppState.php b/src/App/StateMutationResponse/AppState.php new file mode 100644 index 0000000..b7b06ee --- /dev/null +++ b/src/App/StateMutationResponse/AppState.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse; + +use BeeperDesktop\App\StateMutationResponse\AppState\E2ee; +use BeeperDesktop\App\StateMutationResponse\AppState\Matrix; +use BeeperDesktop\App\StateMutationResponse\AppState\State; +use BeeperDesktop\App\StateMutationResponse\AppState\Verification; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Current onboarding state after the requested step. + * + * @phpstan-import-type E2eeShape from \BeeperDesktop\App\StateMutationResponse\AppState\E2ee + * @phpstan-import-type MatrixShape from \BeeperDesktop\App\StateMutationResponse\AppState\Matrix + * @phpstan-import-type VerificationShape from \BeeperDesktop\App\StateMutationResponse\AppState\Verification + * + * @phpstan-type AppStateShape = array{ + * e2ee: E2ee|E2eeShape, + * state: State|value-of<State>, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppState implements BaseModel +{ + /** @use SdkModel<AppStateShape> */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of<State> $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppState::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppState)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of<State> $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of<State> $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/App/StateMutationResponse/AppState/E2ee.php b/src/App/StateMutationResponse/AppState/E2ee.php new file mode 100644 index 0000000..1ed78a5 --- /dev/null +++ b/src/App/StateMutationResponse/AppState/E2ee.php @@ -0,0 +1,260 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse\AppState; + +use BeeperDesktop\App\StateMutationResponse\AppState\E2ee\Secrets; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging setup status. + * + * @phpstan-import-type SecretsShape from \BeeperDesktop\App\StateMutationResponse\AppState\E2ee\Secrets + * + * @phpstan-type E2eeShape = array{ + * crossSigning: bool, + * firstSyncDone: bool, + * hasBackedUpCode: bool, + * initialized: bool, + * keyBackup: bool, + * secrets: Secrets|SecretsShape, + * secretStorage: bool, + * verified: bool, + * recoveryCodeGeneratedAt?: float|null, + * } + */ +final class E2ee implements BaseModel +{ + /** @use SdkModel<E2eeShape> */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/App/StateMutationResponse/AppState/E2ee/Secrets.php b/src/App/StateMutationResponse/AppState/E2ee/Secrets.php new file mode 100644 index 0000000..1e54a66 --- /dev/null +++ b/src/App/StateMutationResponse/AppState/E2ee/Secrets.php @@ -0,0 +1,164 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse\AppState\E2ee; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging keys available on this device. + * + * @phpstan-type SecretsShape = array{ + * masterKey: bool, + * megolmBackupKey: bool, + * recoveryCode: bool, + * selfSigningKey: bool, + * userSigningKey: bool, + * } + */ +final class Secrets implements BaseModel +{ + /** @use SdkModel<SecretsShape> */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/App/StateMutationResponse/AppState/Matrix.php b/src/App/StateMutationResponse/AppState/Matrix.php new file mode 100644 index 0000000..d0e8960 --- /dev/null +++ b/src/App/StateMutationResponse/AppState/Matrix.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse\AppState; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Signed-in account details. Omitted until sign-in is complete. + * + * @phpstan-type MatrixShape = array{ + * deviceID: string, homeserver: string, userID: string + * } + */ +final class Matrix implements BaseModel +{ + /** @use SdkModel<MatrixShape> */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/App/StateMutationResponse/AppState/State.php b/src/App/StateMutationResponse/AppState/State.php new file mode 100644 index 0000000..fb9c1d1 --- /dev/null +++ b/src/App/StateMutationResponse/AppState/State.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse\AppState; + +/** + * Current onboarding state for Beeper Desktop. + */ +enum State: string +{ + case NEEDS_LOGIN = 'needs-login'; + + case INITIALIZING = 'initializing'; + + case NEEDS_CROSS_SIGNING_SETUP = 'needs-cross-signing-setup'; + + case NEEDS_VERIFICATION = 'needs-verification'; + + case NEEDS_SECRETS = 'needs-secrets'; + + case NEEDS_FIRST_SYNC = 'needs-first-sync'; + + case READY = 'ready'; +} diff --git a/src/App/StateMutationResponse/AppState/Verification.php b/src/App/StateMutationResponse/AppState/Verification.php new file mode 100644 index 0000000..4564a39 --- /dev/null +++ b/src/App/StateMutationResponse/AppState/Verification.php @@ -0,0 +1,302 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse\AppState; + +use BeeperDesktop\App\StateMutationResponse\AppState\Verification\AvailableAction; +use BeeperDesktop\App\StateMutationResponse\AppState\Verification\Error; +use BeeperDesktop\App\StateMutationResponse\AppState\Verification\Sas; +use BeeperDesktop\App\StateMutationResponse\AppState\Verification\State; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Trusted-device verification progress. + * + * @phpstan-import-type ErrorShape from \BeeperDesktop\App\StateMutationResponse\AppState\Verification\Error + * @phpstan-import-type SasShape from \BeeperDesktop\App\StateMutationResponse\AppState\Verification\Sas + * + * @phpstan-type VerificationShape = array{ + * availableActions: list<AvailableAction|value-of<AvailableAction>>, + * state: \BeeperDesktop\App\StateMutationResponse\AppState\Verification\State|value-of<\BeeperDesktop\App\StateMutationResponse\AppState\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel<VerificationShape> */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list<value-of<AvailableAction>> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of<State> $state + */ + #[Required( + enum: State::class, + )] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + * @param State|value-of<State> $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of<State> $state + */ + public function withState( + State|string $state, + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/App/StateMutationResponse/AppState/Verification/AvailableAction.php b/src/App/StateMutationResponse/AppState/Verification/AvailableAction.php new file mode 100644 index 0000000..5fbb282 --- /dev/null +++ b/src/App/StateMutationResponse/AppState/Verification/AvailableAction.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse\AppState\Verification; + +enum AvailableAction: string +{ + case CREATE = 'create'; + + case QR_SCAN = 'qr.scan'; + + case ACCEPT = 'accept'; + + case CANCEL = 'cancel'; + + case QR_CONFIRM_SCANNED = 'qr.confirmScanned'; + + case SAS_START = 'sas.start'; + + case SAS_CONFIRM = 'sas.confirm'; +} diff --git a/src/App/StateMutationResponse/AppState/Verification/Error.php b/src/App/StateMutationResponse/AppState/Verification/Error.php new file mode 100644 index 0000000..4d94568 --- /dev/null +++ b/src/App/StateMutationResponse/AppState/Verification/Error.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Verification error details, if verification stopped. + * + * @phpstan-type ErrorShape = array{code: string, reason: string} + */ +final class Error implements BaseModel +{ + /** @use SdkModel<ErrorShape> */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/App/StateMutationResponse/AppState/Verification/Sas.php b/src/App/StateMutationResponse/AppState/Verification/Sas.php new file mode 100644 index 0000000..fa65796 --- /dev/null +++ b/src/App/StateMutationResponse/AppState/Verification/Sas.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse\AppState\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Emoji or number comparison data for verification. + * + * @phpstan-type SasShape = array{decimals: string, emojis: string} + */ +final class Sas implements BaseModel +{ + /** @use SdkModel<SasShape> */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/App/StateMutationResponse/AppState/Verification/State.php b/src/App/StateMutationResponse/AppState/Verification/State.php new file mode 100644 index 0000000..b9e7d5e --- /dev/null +++ b/src/App/StateMutationResponse/AppState/Verification/State.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\App\StateMutationResponse\AppState\Verification; + +/** + * Current trusted-device verification state. + */ +enum State: string +{ + case IDLE = 'idle'; + + case REQUESTED = 'requested'; + + case READY = 'ready'; + + case SAS_READY = 'sas_ready'; + + case QR_SCANNED = 'qr_scanned'; + + case DONE = 'done'; + + case CANCELLED = 'cancelled'; + + case ERROR = 'error'; +} diff --git a/src/AppStateSnapshot.php b/src/AppStateSnapshot.php new file mode 100644 index 0000000..faf7742 --- /dev/null +++ b/src/AppStateSnapshot.php @@ -0,0 +1,156 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop; + +use BeeperDesktop\AppStateSnapshot\E2ee; +use BeeperDesktop\AppStateSnapshot\Matrix; +use BeeperDesktop\AppStateSnapshot\State; +use BeeperDesktop\AppStateSnapshot\Verification; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-import-type E2eeShape from \BeeperDesktop\AppStateSnapshot\E2ee + * @phpstan-import-type MatrixShape from \BeeperDesktop\AppStateSnapshot\Matrix + * @phpstan-import-type VerificationShape from \BeeperDesktop\AppStateSnapshot\Verification + * + * @phpstan-type AppStateSnapshotShape = array{ + * e2ee: E2ee|E2eeShape, + * state: State|value-of<State>, + * matrix?: null|Matrix|MatrixShape, + * verification?: null|Verification|VerificationShape, + * } + */ +final class AppStateSnapshot implements BaseModel +{ + /** @use SdkModel<AppStateSnapshotShape> */ + use SdkModel; + + /** + * Encrypted messaging setup status. + */ + #[Required] + public E2ee $e2ee; + + /** + * Current onboarding state for Beeper Desktop. + * + * @var value-of<State> $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Signed-in account details. Omitted until sign-in is complete. + */ + #[Optional] + public ?Matrix $matrix; + + /** + * Trusted-device verification progress. + */ + #[Optional] + public ?Verification $verification; + + /** + * `new AppStateSnapshot()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AppStateSnapshot::with(e2ee: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AppStateSnapshot)->withE2ee(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param E2ee|E2eeShape $e2ee + * @param State|value-of<State> $state + * @param Matrix|MatrixShape|null $matrix + * @param Verification|VerificationShape|null $verification + */ + public static function with( + E2ee|array $e2ee, + State|string $state, + Matrix|array|null $matrix = null, + Verification|array|null $verification = null, + ): self { + $self = new self; + + $self['e2ee'] = $e2ee; + $self['state'] = $state; + + null !== $matrix && $self['matrix'] = $matrix; + null !== $verification && $self['verification'] = $verification; + + return $self; + } + + /** + * Encrypted messaging setup status. + * + * @param E2ee|E2eeShape $e2ee + */ + public function withE2ee(E2ee|array $e2ee): self + { + $self = clone $this; + $self['e2ee'] = $e2ee; + + return $self; + } + + /** + * Current onboarding state for Beeper Desktop. + * + * @param State|value-of<State> $state + */ + public function withState(State|string $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Signed-in account details. Omitted until sign-in is complete. + * + * @param Matrix|MatrixShape $matrix + */ + public function withMatrix(Matrix|array $matrix): self + { + $self = clone $this; + $self['matrix'] = $matrix; + + return $self; + } + + /** + * Trusted-device verification progress. + * + * @param Verification|VerificationShape $verification + */ + public function withVerification(Verification|array $verification): self + { + $self = clone $this; + $self['verification'] = $verification; + + return $self; + } +} diff --git a/src/AppStateSnapshot/E2ee.php b/src/AppStateSnapshot/E2ee.php new file mode 100644 index 0000000..b73e5de --- /dev/null +++ b/src/AppStateSnapshot/E2ee.php @@ -0,0 +1,260 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\AppStateSnapshot; + +use BeeperDesktop\AppStateSnapshot\E2ee\Secrets; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging setup status. + * + * @phpstan-import-type SecretsShape from \BeeperDesktop\AppStateSnapshot\E2ee\Secrets + * + * @phpstan-type E2eeShape = array{ + * crossSigning: bool, + * firstSyncDone: bool, + * hasBackedUpCode: bool, + * initialized: bool, + * keyBackup: bool, + * secrets: Secrets|SecretsShape, + * secretStorage: bool, + * verified: bool, + * recoveryCodeGeneratedAt?: float|null, + * } + */ +final class E2ee implements BaseModel +{ + /** @use SdkModel<E2eeShape> */ + use SdkModel; + + /** + * Whether this account can verify trusted devices. + */ + #[Required] + public bool $crossSigning; + + /** + * Whether the first encrypted message sync is complete. + */ + #[Required] + public bool $firstSyncDone; + + /** + * Whether the user confirmed that they saved their recovery key. + */ + #[Required] + public bool $hasBackedUpCode; + + /** + * Whether encrypted messaging setup has started. + */ + #[Required] + public bool $initialized; + + /** + * Whether encrypted message backup is available. + */ + #[Required] + public bool $keyBackup; + + /** + * Encrypted messaging keys available on this device. + */ + #[Required] + public Secrets $secrets; + + /** + * Whether secure key storage is available. + */ + #[Required] + public bool $secretStorage; + + /** + * Whether this device is trusted for encrypted messages. + */ + #[Required] + public bool $verified; + + /** + * Unix timestamp for when the recovery key was created. + */ + #[Optional] + public ?float $recoveryCodeGeneratedAt; + + /** + * `new E2ee()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * E2ee::with( + * crossSigning: ..., + * firstSyncDone: ..., + * hasBackedUpCode: ..., + * initialized: ..., + * keyBackup: ..., + * secrets: ..., + * secretStorage: ..., + * verified: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new E2ee) + * ->withCrossSigning(...) + * ->withFirstSyncDone(...) + * ->withHasBackedUpCode(...) + * ->withInitialized(...) + * ->withKeyBackup(...) + * ->withSecrets(...) + * ->withSecretStorage(...) + * ->withVerified(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Secrets|SecretsShape $secrets + */ + public static function with( + bool $crossSigning, + bool $firstSyncDone, + bool $hasBackedUpCode, + bool $initialized, + bool $keyBackup, + Secrets|array $secrets, + bool $secretStorage, + bool $verified, + ?float $recoveryCodeGeneratedAt = null, + ): self { + $self = new self; + + $self['crossSigning'] = $crossSigning; + $self['firstSyncDone'] = $firstSyncDone; + $self['hasBackedUpCode'] = $hasBackedUpCode; + $self['initialized'] = $initialized; + $self['keyBackup'] = $keyBackup; + $self['secrets'] = $secrets; + $self['secretStorage'] = $secretStorage; + $self['verified'] = $verified; + + null !== $recoveryCodeGeneratedAt && $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } + + /** + * Whether this account can verify trusted devices. + */ + public function withCrossSigning(bool $crossSigning): self + { + $self = clone $this; + $self['crossSigning'] = $crossSigning; + + return $self; + } + + /** + * Whether the first encrypted message sync is complete. + */ + public function withFirstSyncDone(bool $firstSyncDone): self + { + $self = clone $this; + $self['firstSyncDone'] = $firstSyncDone; + + return $self; + } + + /** + * Whether the user confirmed that they saved their recovery key. + */ + public function withHasBackedUpCode(bool $hasBackedUpCode): self + { + $self = clone $this; + $self['hasBackedUpCode'] = $hasBackedUpCode; + + return $self; + } + + /** + * Whether encrypted messaging setup has started. + */ + public function withInitialized(bool $initialized): self + { + $self = clone $this; + $self['initialized'] = $initialized; + + return $self; + } + + /** + * Whether encrypted message backup is available. + */ + public function withKeyBackup(bool $keyBackup): self + { + $self = clone $this; + $self['keyBackup'] = $keyBackup; + + return $self; + } + + /** + * Encrypted messaging keys available on this device. + * + * @param Secrets|SecretsShape $secrets + */ + public function withSecrets(Secrets|array $secrets): self + { + $self = clone $this; + $self['secrets'] = $secrets; + + return $self; + } + + /** + * Whether secure key storage is available. + */ + public function withSecretStorage(bool $secretStorage): self + { + $self = clone $this; + $self['secretStorage'] = $secretStorage; + + return $self; + } + + /** + * Whether this device is trusted for encrypted messages. + */ + public function withVerified(bool $verified): self + { + $self = clone $this; + $self['verified'] = $verified; + + return $self; + } + + /** + * Unix timestamp for when the recovery key was created. + */ + public function withRecoveryCodeGeneratedAt( + float $recoveryCodeGeneratedAt + ): self { + $self = clone $this; + $self['recoveryCodeGeneratedAt'] = $recoveryCodeGeneratedAt; + + return $self; + } +} diff --git a/src/AppStateSnapshot/E2ee/Secrets.php b/src/AppStateSnapshot/E2ee/Secrets.php new file mode 100644 index 0000000..5cf9275 --- /dev/null +++ b/src/AppStateSnapshot/E2ee/Secrets.php @@ -0,0 +1,164 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\AppStateSnapshot\E2ee; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Encrypted messaging keys available on this device. + * + * @phpstan-type SecretsShape = array{ + * masterKey: bool, + * megolmBackupKey: bool, + * recoveryCode: bool, + * selfSigningKey: bool, + * userSigningKey: bool, + * } + */ +final class Secrets implements BaseModel +{ + /** @use SdkModel<SecretsShape> */ + use SdkModel; + + /** + * Whether the account identity key is available. + */ + #[Required] + public bool $masterKey; + + /** + * Whether the encrypted message backup key is available. + */ + #[Required] + public bool $megolmBackupKey; + + /** + * Whether a recovery key is available. + */ + #[Required] + public bool $recoveryCode; + + /** + * Whether the device trust key is available. + */ + #[Required] + public bool $selfSigningKey; + + /** + * Whether the user trust key is available. + */ + #[Required] + public bool $userSigningKey; + + /** + * `new Secrets()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Secrets::with( + * masterKey: ..., + * megolmBackupKey: ..., + * recoveryCode: ..., + * selfSigningKey: ..., + * userSigningKey: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Secrets) + * ->withMasterKey(...) + * ->withMegolmBackupKey(...) + * ->withRecoveryCode(...) + * ->withSelfSigningKey(...) + * ->withUserSigningKey(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + bool $masterKey, + bool $megolmBackupKey, + bool $recoveryCode, + bool $selfSigningKey, + bool $userSigningKey, + ): self { + $self = new self; + + $self['masterKey'] = $masterKey; + $self['megolmBackupKey'] = $megolmBackupKey; + $self['recoveryCode'] = $recoveryCode; + $self['selfSigningKey'] = $selfSigningKey; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } + + /** + * Whether the account identity key is available. + */ + public function withMasterKey(bool $masterKey): self + { + $self = clone $this; + $self['masterKey'] = $masterKey; + + return $self; + } + + /** + * Whether the encrypted message backup key is available. + */ + public function withMegolmBackupKey(bool $megolmBackupKey): self + { + $self = clone $this; + $self['megolmBackupKey'] = $megolmBackupKey; + + return $self; + } + + /** + * Whether a recovery key is available. + */ + public function withRecoveryCode(bool $recoveryCode): self + { + $self = clone $this; + $self['recoveryCode'] = $recoveryCode; + + return $self; + } + + /** + * Whether the device trust key is available. + */ + public function withSelfSigningKey(bool $selfSigningKey): self + { + $self = clone $this; + $self['selfSigningKey'] = $selfSigningKey; + + return $self; + } + + /** + * Whether the user trust key is available. + */ + public function withUserSigningKey(bool $userSigningKey): self + { + $self = clone $this; + $self['userSigningKey'] = $userSigningKey; + + return $self; + } +} diff --git a/src/AppStateSnapshot/Matrix.php b/src/AppStateSnapshot/Matrix.php new file mode 100644 index 0000000..c5acb1b --- /dev/null +++ b/src/AppStateSnapshot/Matrix.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\AppStateSnapshot; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Signed-in account details. Omitted until sign-in is complete. + * + * @phpstan-type MatrixShape = array{ + * deviceID: string, homeserver: string, userID: string + * } + */ +final class Matrix implements BaseModel +{ + /** @use SdkModel<MatrixShape> */ + use SdkModel; + + /** + * Current device ID. + */ + #[Required] + public string $deviceID; + + /** + * Beeper server URL for this account. + */ + #[Required] + public string $homeserver; + + /** + * Signed-in Beeper user ID. + */ + #[Required] + public string $userID; + + /** + * `new Matrix()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Matrix::with(deviceID: ..., homeserver: ..., userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Matrix)->withDeviceID(...)->withHomeserver(...)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $deviceID, + string $homeserver, + string $userID + ): self { + $self = new self; + + $self['deviceID'] = $deviceID; + $self['homeserver'] = $homeserver; + $self['userID'] = $userID; + + return $self; + } + + /** + * Current device ID. + */ + public function withDeviceID(string $deviceID): self + { + $self = clone $this; + $self['deviceID'] = $deviceID; + + return $self; + } + + /** + * Beeper server URL for this account. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * Signed-in Beeper user ID. + */ + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/AppStateSnapshot/State.php b/src/AppStateSnapshot/State.php new file mode 100644 index 0000000..68c6a1d --- /dev/null +++ b/src/AppStateSnapshot/State.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\AppStateSnapshot; + +/** + * Current onboarding state for Beeper Desktop. + */ +enum State: string +{ + case NEEDS_LOGIN = 'needs-login'; + + case INITIALIZING = 'initializing'; + + case NEEDS_CROSS_SIGNING_SETUP = 'needs-cross-signing-setup'; + + case NEEDS_VERIFICATION = 'needs-verification'; + + case NEEDS_SECRETS = 'needs-secrets'; + + case NEEDS_FIRST_SYNC = 'needs-first-sync'; + + case READY = 'ready'; +} diff --git a/src/AppStateSnapshot/Verification.php b/src/AppStateSnapshot/Verification.php new file mode 100644 index 0000000..64cb662 --- /dev/null +++ b/src/AppStateSnapshot/Verification.php @@ -0,0 +1,300 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\AppStateSnapshot; + +use BeeperDesktop\AppStateSnapshot\Verification\AvailableAction; +use BeeperDesktop\AppStateSnapshot\Verification\Error; +use BeeperDesktop\AppStateSnapshot\Verification\Sas; +use BeeperDesktop\AppStateSnapshot\Verification\State; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Trusted-device verification progress. + * + * @phpstan-import-type ErrorShape from \BeeperDesktop\AppStateSnapshot\Verification\Error + * @phpstan-import-type SasShape from \BeeperDesktop\AppStateSnapshot\Verification\Sas + * + * @phpstan-type VerificationShape = array{ + * availableActions: list<AvailableAction|value-of<AvailableAction>>, + * state: \BeeperDesktop\AppStateSnapshot\Verification\State|value-of<\BeeperDesktop\AppStateSnapshot\Verification\State>, + * error?: null|Error|ErrorShape, + * from?: string|null, + * fromDevice?: string|null, + * otherDevice?: string|null, + * qrData?: string|null, + * sas?: null|Sas|SasShape, + * supportsSas?: bool|null, + * supportsScanQrCode?: bool|null, + * verificationID?: string|null, + * } + */ +final class Verification implements BaseModel +{ + /** @use SdkModel<VerificationShape> */ + use SdkModel; + + /** + * Verification actions that are valid for the current state. + * + * @var list<value-of<AvailableAction>> $availableActions + */ + #[Required(list: AvailableAction::class)] + public array $availableActions; + + /** + * Current trusted-device verification state. + * + * @var value-of<State> $state + */ + #[Required(enum: State::class)] + public string $state; + + /** + * Verification error details, if verification stopped. + */ + #[Optional] + public ?Error $error; + + /** + * User ID that started verification. + */ + #[Optional] + public ?string $from; + + /** + * Device that started verification. + */ + #[Optional] + public ?string $fromDevice; + + /** + * Other device participating in verification. + */ + #[Optional] + public ?string $otherDevice; + + /** + * QR code payload to display for verification. + */ + #[Optional] + public ?string $qrData; + + /** + * Emoji or number comparison data for verification. + */ + #[Optional] + public ?Sas $sas; + + /** + * Whether emoji comparison is available. + */ + #[Optional('supportsSAS')] + public ?bool $supportsSas; + + /** + * Whether QR code verification is available. + */ + #[Optional('supportsScanQRCode')] + public ?bool $supportsScanQrCode; + + /** + * Verification ID to pass in verification action paths. + */ + #[Optional] + public ?string $verificationID; + + /** + * `new Verification()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Verification::with(availableActions: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Verification)->withAvailableActions(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + * @param State|value-of<State> $state + * @param Error|ErrorShape|null $error + * @param Sas|SasShape|null $sas + */ + public static function with( + array $availableActions, + State|string $state, + Error|array|null $error = null, + ?string $from = null, + ?string $fromDevice = null, + ?string $otherDevice = null, + ?string $qrData = null, + Sas|array|null $sas = null, + ?bool $supportsSas = null, + ?bool $supportsScanQrCode = null, + ?string $verificationID = null, + ): self { + $self = new self; + + $self['availableActions'] = $availableActions; + $self['state'] = $state; + + null !== $error && $self['error'] = $error; + null !== $from && $self['from'] = $from; + null !== $fromDevice && $self['fromDevice'] = $fromDevice; + null !== $otherDevice && $self['otherDevice'] = $otherDevice; + null !== $qrData && $self['qrData'] = $qrData; + null !== $sas && $self['sas'] = $sas; + null !== $supportsSas && $self['supportsSas'] = $supportsSas; + null !== $supportsScanQrCode && $self['supportsScanQrCode'] = $supportsScanQrCode; + null !== $verificationID && $self['verificationID'] = $verificationID; + + return $self; + } + + /** + * Verification actions that are valid for the current state. + * + * @param list<AvailableAction|value-of<AvailableAction>> $availableActions + */ + public function withAvailableActions(array $availableActions): self + { + $self = clone $this; + $self['availableActions'] = $availableActions; + + return $self; + } + + /** + * Current trusted-device verification state. + * + * @param State|value-of<State> $state + */ + public function withState( + State|string $state + ): self { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * Verification error details, if verification stopped. + * + * @param Error|ErrorShape $error + */ + public function withError(Error|array $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * User ID that started verification. + */ + public function withFrom(string $from): self + { + $self = clone $this; + $self['from'] = $from; + + return $self; + } + + /** + * Device that started verification. + */ + public function withFromDevice(string $fromDevice): self + { + $self = clone $this; + $self['fromDevice'] = $fromDevice; + + return $self; + } + + /** + * Other device participating in verification. + */ + public function withOtherDevice(string $otherDevice): self + { + $self = clone $this; + $self['otherDevice'] = $otherDevice; + + return $self; + } + + /** + * QR code payload to display for verification. + */ + public function withQrData(string $qrData): self + { + $self = clone $this; + $self['qrData'] = $qrData; + + return $self; + } + + /** + * Emoji or number comparison data for verification. + * + * @param Sas|SasShape $sas + */ + public function withSas(Sas|array $sas): self + { + $self = clone $this; + $self['sas'] = $sas; + + return $self; + } + + /** + * Whether emoji comparison is available. + */ + public function withSupportsSas(bool $supportsSas): self + { + $self = clone $this; + $self['supportsSas'] = $supportsSas; + + return $self; + } + + /** + * Whether QR code verification is available. + */ + public function withSupportsScanQrCode(bool $supportsScanQrCode): self + { + $self = clone $this; + $self['supportsScanQrCode'] = $supportsScanQrCode; + + return $self; + } + + /** + * Verification ID to pass in verification action paths. + */ + public function withVerificationID(string $verificationID): self + { + $self = clone $this; + $self['verificationID'] = $verificationID; + + return $self; + } +} diff --git a/src/AppStateSnapshot/Verification/AvailableAction.php b/src/AppStateSnapshot/Verification/AvailableAction.php new file mode 100644 index 0000000..a1a8665 --- /dev/null +++ b/src/AppStateSnapshot/Verification/AvailableAction.php @@ -0,0 +1,22 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\AppStateSnapshot\Verification; + +enum AvailableAction: string +{ + case CREATE = 'create'; + + case QR_SCAN = 'qr.scan'; + + case ACCEPT = 'accept'; + + case CANCEL = 'cancel'; + + case QR_CONFIRM_SCANNED = 'qr.confirmScanned'; + + case SAS_START = 'sas.start'; + + case SAS_CONFIRM = 'sas.confirm'; +} diff --git a/src/AppStateSnapshot/Verification/Error.php b/src/AppStateSnapshot/Verification/Error.php new file mode 100644 index 0000000..2ac160f --- /dev/null +++ b/src/AppStateSnapshot/Verification/Error.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\AppStateSnapshot\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Verification error details, if verification stopped. + * + * @phpstan-type ErrorShape = array{code: string, reason: string} + */ +final class Error implements BaseModel +{ + /** @use SdkModel<ErrorShape> */ + use SdkModel; + + /** + * Verification error code. + */ + #[Required] + public string $code; + + /** + * User-facing verification error message. + */ + #[Required] + public string $reason; + + /** + * `new Error()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Error::with(code: ..., reason: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Error)->withCode(...)->withReason(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $code, string $reason): self + { + $self = new self; + + $self['code'] = $code; + $self['reason'] = $reason; + + return $self; + } + + /** + * Verification error code. + */ + public function withCode(string $code): self + { + $self = clone $this; + $self['code'] = $code; + + return $self; + } + + /** + * User-facing verification error message. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/AppStateSnapshot/Verification/Sas.php b/src/AppStateSnapshot/Verification/Sas.php new file mode 100644 index 0000000..85af567 --- /dev/null +++ b/src/AppStateSnapshot/Verification/Sas.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\AppStateSnapshot\Verification; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Emoji or number comparison data for verification. + * + * @phpstan-type SasShape = array{decimals: string, emojis: string} + */ +final class Sas implements BaseModel +{ + /** @use SdkModel<SasShape> */ + use SdkModel; + + /** + * Number sequence to compare on both devices. + */ + #[Required] + public string $decimals; + + /** + * Emoji sequence to compare on both devices. + */ + #[Required] + public string $emojis; + + /** + * `new Sas()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Sas::with(decimals: ..., emojis: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Sas)->withDecimals(...)->withEmojis(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $decimals, string $emojis): self + { + $self = new self; + + $self['decimals'] = $decimals; + $self['emojis'] = $emojis; + + return $self; + } + + /** + * Number sequence to compare on both devices. + */ + public function withDecimals(string $decimals): self + { + $self = clone $this; + $self['decimals'] = $decimals; + + return $self; + } + + /** + * Emoji sequence to compare on both devices. + */ + public function withEmojis(string $emojis): self + { + $self = clone $this; + $self['emojis'] = $emojis; + + return $self; + } +} diff --git a/src/AppStateSnapshot/Verification/State.php b/src/AppStateSnapshot/Verification/State.php new file mode 100644 index 0000000..01f0890 --- /dev/null +++ b/src/AppStateSnapshot/Verification/State.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\AppStateSnapshot\Verification; + +/** + * Current trusted-device verification state. + */ +enum State: string +{ + case IDLE = 'idle'; + + case REQUESTED = 'requested'; + + case READY = 'ready'; + + case SAS_READY = 'sas_ready'; + + case QR_SCANNED = 'qr_scanned'; + + case DONE = 'done'; + + case CANCELLED = 'cancelled'; + + case ERROR = 'error'; +} diff --git a/src/Bridges/BridgeAvailability.php b/src/Bridges/BridgeAvailability.php new file mode 100644 index 0000000..e86cda7 --- /dev/null +++ b/src/Bridges/BridgeAvailability.php @@ -0,0 +1,248 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Bridges; + +use BeeperDesktop\Accounts\Account; +use BeeperDesktop\Bridges\BridgeAvailability\Bridge; +use BeeperDesktop\Bridges\BridgeAvailability\Status; +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Bridge-backed account type that can be shown in add-account flows. + * + * @phpstan-import-type AccountShape from \BeeperDesktop\Accounts\Account + * @phpstan-import-type BridgeShape from \BeeperDesktop\Bridges\BridgeAvailability\Bridge + * + * @phpstan-type BridgeAvailabilityShape = array{ + * accounts: list<Account|AccountShape>, + * activeAccountCount: int, + * bridge: Bridge|BridgeShape, + * displayName: string, + * loginMode: string, + * status: Status|value-of<Status>, + * network?: string|null, + * statusText?: string|null, + * } + */ +final class BridgeAvailability implements BaseModel +{ + /** @use SdkModel<BridgeAvailabilityShape> */ + use SdkModel; + + /** + * Connected accounts for this bridge. Uses the same Account schema as GET /v1/accounts. + * + * @var list<Account> $accounts + */ + #[Required(list: Account::class)] + public array $accounts; + + /** + * Number of active accounts for this network on this device. + */ + #[Required] + public int $activeAccountCount; + + /** + * Bridge metadata for the account. Available in Beeper Desktop v4.2.785+. + */ + #[Required] + public Bridge $bridge; + + /** + * Human-friendly account type name shown in Beeper Desktop. + */ + #[Required] + public string $displayName; + + /** + * Login mode used by Beeper Desktop for this bridge. + */ + #[Required] + public string $loginMode; + + /** + * Whether this bridge can currently be used to add an account. + * + * @var value-of<Status> $status + */ + #[Required(enum: Status::class)] + public string $status; + + /** + * Network grouping used for account counts and limits. + */ + #[Optional] + public ?string $network; + + /** + * Human-friendly status text matching Beeper Desktop account management language. + */ + #[Optional] + public ?string $statusText; + + /** + * `new BridgeAvailability()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * BridgeAvailability::with( + * accounts: ..., + * activeAccountCount: ..., + * bridge: ..., + * displayName: ..., + * loginMode: ..., + * status: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new BridgeAvailability) + * ->withAccounts(...) + * ->withActiveAccountCount(...) + * ->withBridge(...) + * ->withDisplayName(...) + * ->withLoginMode(...) + * ->withStatus(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Account|AccountShape> $accounts + * @param Bridge|BridgeShape $bridge + * @param Status|value-of<Status> $status + */ + public static function with( + array $accounts, + int $activeAccountCount, + Bridge|array $bridge, + string $displayName, + string $loginMode, + Status|string $status, + ?string $network = null, + ?string $statusText = null, + ): self { + $self = new self; + + $self['accounts'] = $accounts; + $self['activeAccountCount'] = $activeAccountCount; + $self['bridge'] = $bridge; + $self['displayName'] = $displayName; + $self['loginMode'] = $loginMode; + $self['status'] = $status; + + null !== $network && $self['network'] = $network; + null !== $statusText && $self['statusText'] = $statusText; + + return $self; + } + + /** + * Connected accounts for this bridge. Uses the same Account schema as GET /v1/accounts. + * + * @param list<Account|AccountShape> $accounts + */ + public function withAccounts(array $accounts): self + { + $self = clone $this; + $self['accounts'] = $accounts; + + return $self; + } + + /** + * Number of active accounts for this network on this device. + */ + public function withActiveAccountCount(int $activeAccountCount): self + { + $self = clone $this; + $self['activeAccountCount'] = $activeAccountCount; + + return $self; + } + + /** + * Bridge metadata for the account. Available in Beeper Desktop v4.2.785+. + * + * @param Bridge|BridgeShape $bridge + */ + public function withBridge(Bridge|array $bridge): self + { + $self = clone $this; + $self['bridge'] = $bridge; + + return $self; + } + + /** + * Human-friendly account type name shown in Beeper Desktop. + */ + public function withDisplayName(string $displayName): self + { + $self = clone $this; + $self['displayName'] = $displayName; + + return $self; + } + + /** + * Login mode used by Beeper Desktop for this bridge. + */ + public function withLoginMode(string $loginMode): self + { + $self = clone $this; + $self['loginMode'] = $loginMode; + + return $self; + } + + /** + * Whether this bridge can currently be used to add an account. + * + * @param Status|value-of<Status> $status + */ + public function withStatus(Status|string $status): self + { + $self = clone $this; + $self['status'] = $status; + + return $self; + } + + /** + * Network grouping used for account counts and limits. + */ + public function withNetwork(string $network): self + { + $self = clone $this; + $self['network'] = $network; + + return $self; + } + + /** + * Human-friendly status text matching Beeper Desktop account management language. + */ + public function withStatusText(string $statusText): self + { + $self = clone $this; + $self['statusText'] = $statusText; + + return $self; + } +} diff --git a/src/Bridges/BridgeAvailability/Bridge.php b/src/Bridges/BridgeAvailability/Bridge.php new file mode 100644 index 0000000..cd5a1da --- /dev/null +++ b/src/Bridges/BridgeAvailability/Bridge.php @@ -0,0 +1,118 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Bridges\BridgeAvailability; + +use BeeperDesktop\Bridges\BridgeAvailability\Bridge\Provider; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Bridge metadata for the account. Available in Beeper Desktop v4.2.785+. + * + * @phpstan-type BridgeShape = array{ + * id: string, provider: Provider|value-of<Provider>, type: string + * } + */ +final class Bridge implements BaseModel +{ + /** @use SdkModel<BridgeShape> */ + use SdkModel; + + /** + * 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+. + */ + #[Required] + public string $id; + + /** + * Bridge provider for the account. Available in Beeper Desktop v4.2.785+. + * + * @var value-of<Provider> $provider + */ + #[Required(enum: Provider::class)] + public string $provider; + + /** + * Bridge type, such as matrix, discordgo, slackgo, whatsapp, telegram, or twitter. Available in Beeper Desktop v4.2.785+. + */ + #[Required] + public string $type; + + /** + * `new Bridge()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Bridge::with(id: ..., provider: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Bridge)->withID(...)->withProvider(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Provider|value-of<Provider> $provider + */ + public static function with( + string $id, + Provider|string $provider, + string $type + ): self { + $self = new self; + + $self['id'] = $id; + $self['provider'] = $provider; + $self['type'] = $type; + + return $self; + } + + /** + * 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+. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * Bridge provider for the account. Available in Beeper Desktop v4.2.785+. + * + * @param Provider|value-of<Provider> $provider + */ + public function withProvider(Provider|string $provider): self + { + $self = clone $this; + $self['provider'] = $provider; + + return $self; + } + + /** + * Bridge type, such as matrix, discordgo, slackgo, whatsapp, telegram, or twitter. Available in Beeper Desktop v4.2.785+. + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } +} diff --git a/src/Bridges/BridgeAvailability/Bridge/Provider.php b/src/Bridges/BridgeAvailability/Bridge/Provider.php new file mode 100644 index 0000000..d3df0bb --- /dev/null +++ b/src/Bridges/BridgeAvailability/Bridge/Provider.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Bridges\BridgeAvailability\Bridge; + +/** + * Bridge provider for the account. Available in Beeper Desktop v4.2.785+. + */ +enum Provider: string +{ + case CLOUD = 'cloud'; + + case SELF_HOSTED = 'self-hosted'; + + case LOCAL = 'local'; + + case PLATFORM_SDK = 'platform-sdk'; +} diff --git a/src/Bridges/BridgeAvailability/Status.php b/src/Bridges/BridgeAvailability/Status.php new file mode 100644 index 0000000..1abe562 --- /dev/null +++ b/src/Bridges/BridgeAvailability/Status.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Bridges\BridgeAvailability; + +/** + * Whether this bridge can currently be used to add an account. + */ +enum Status: string +{ + case AVAILABLE = 'available'; + + case CONNECTED = 'connected'; + + case LIMIT_REACHED = 'limit_reached'; + + case TEMPORARILY_UNAVAILABLE = 'temporarily_unavailable'; +} diff --git a/src/Bridges/BridgeListResponse.php b/src/Bridges/BridgeListResponse.php new file mode 100644 index 0000000..7edc83c --- /dev/null +++ b/src/Bridges/BridgeListResponse.php @@ -0,0 +1,74 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Bridges; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Bridge-backed account types and their connected accounts. + * + * @phpstan-import-type BridgeAvailabilityShape from \BeeperDesktop\Bridges\BridgeAvailability + * + * @phpstan-type BridgeListResponseShape = array{ + * items: list<BridgeAvailability|BridgeAvailabilityShape> + * } + */ +final class BridgeListResponse implements BaseModel +{ + /** @use SdkModel<BridgeListResponseShape> */ + use SdkModel; + + /** @var list<BridgeAvailability> $items */ + #[Required(list: BridgeAvailability::class)] + public array $items; + + /** + * `new BridgeListResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * BridgeListResponse::with(items: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new BridgeListResponse)->withItems(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<BridgeAvailability|BridgeAvailabilityShape> $items + */ + public static function with(array $items): self + { + $self = new self; + + $self['items'] = $items; + + return $self; + } + + /** + * @param list<BridgeAvailability|BridgeAvailabilityShape> $items + */ + public function withItems(array $items): self + { + $self = clone $this; + $self['items'] = $items; + + return $self; + } +} diff --git a/src/Client.php b/src/Client.php index eadd4d1..9595110 100644 --- a/src/Client.php +++ b/src/Client.php @@ -11,11 +11,14 @@ use BeeperDesktop\Core\Implementation\StreamingHttpClient; use BeeperDesktop\Core\Util; use BeeperDesktop\Services\AccountsService; +use BeeperDesktop\Services\AppService; use BeeperDesktop\Services\AssetsService; use BeeperDesktop\Services\BeeperDesktopClientRawService; use BeeperDesktop\Services\BeeperDesktopClientService; +use BeeperDesktop\Services\BridgesService; use BeeperDesktop\Services\ChatsService; use BeeperDesktop\Services\InfoService; +use BeeperDesktop\Services\MatrixService; use BeeperDesktop\Services\MessagesService; use Http\Discovery\Psr17FactoryDiscovery; use Http\Discovery\Psr18ClientDiscovery; @@ -28,11 +31,26 @@ class Client extends BaseClient { public string $accessToken; + /** + * @api + */ + public AppService $app; + /** * @api */ public AccountsService $accounts; + /** + * @api + */ + public BridgesService $bridges; + + /** + * @api + */ + public MatrixService $matrix; + /** * @api */ @@ -121,7 +139,10 @@ public function __construct( options: $options ); + $this->app = new AppService($this); $this->accounts = new AccountsService($this); + $this->bridges = new BridgesService($this); + $this->matrix = new MatrixService($this); $this->chats = new ChatsService($this); $this->messages = new MessagesService($this); $this->assets = new AssetsService($this); diff --git a/src/Matrix/Bridges/Auth/AuthListFlowsResponse.php b/src/Matrix/Bridges/Auth/AuthListFlowsResponse.php new file mode 100644 index 0000000..f366199 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthListFlowsResponse.php @@ -0,0 +1,59 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListFlowsResponse\Flow; + +/** + * @phpstan-import-type FlowShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthListFlowsResponse\Flow + * + * @phpstan-type AuthListFlowsResponseShape = array{ + * flows?: list<Flow|FlowShape>|null + * } + */ +final class AuthListFlowsResponse implements BaseModel +{ + /** @use SdkModel<AuthListFlowsResponseShape> */ + use SdkModel; + + /** @var list<Flow>|null $flows */ + #[Optional(list: Flow::class)] + public ?array $flows; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Flow|FlowShape>|null $flows + */ + public static function with(?array $flows = null): self + { + $self = new self; + + null !== $flows && $self['flows'] = $flows; + + return $self; + } + + /** + * @param list<Flow|FlowShape> $flows + */ + public function withFlows(array $flows): self + { + $self = clone $this; + $self['flows'] = $flows; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthListFlowsResponse/Flow.php b/src/Matrix/Bridges/Auth/AuthListFlowsResponse/Flow.php new file mode 100644 index 0000000..830f642 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthListFlowsResponse/Flow.php @@ -0,0 +1,109 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthListFlowsResponse; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * An individual login flow which can be used to sign into the remote network. + * + * @phpstan-type FlowShape = array{id: string, description: string, name: string} + */ +final class Flow implements BaseModel +{ + /** @use SdkModel<FlowShape> */ + use SdkModel; + + /** + * An internal ID that is passed to the /login/start call to start a login with this flow. + */ + #[Required] + public string $id; + + /** + * A human-readable description of the login flow. + */ + #[Required] + public string $description; + + /** + * A human-readable name for the login flow. + */ + #[Required] + public string $name; + + /** + * `new Flow()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Flow::with(id: ..., description: ..., name: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Flow)->withID(...)->withDescription(...)->withName(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $id, + string $description, + string $name + ): self { + $self = new self; + + $self['id'] = $id; + $self['description'] = $description; + $self['name'] = $name; + + return $self; + } + + /** + * An internal ID that is passed to the /login/start call to start a login with this flow. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * A human-readable description of the login flow. + */ + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * A human-readable name for the login flow. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthListLoginsResponse.php b/src/Matrix/Bridges/Auth/AuthListLoginsResponse.php new file mode 100644 index 0000000..d886382 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthListLoginsResponse.php @@ -0,0 +1,54 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-type AuthListLoginsResponseShape = array{loginIDs?: list<string>|null} + */ +final class AuthListLoginsResponse implements BaseModel +{ + /** @use SdkModel<AuthListLoginsResponseShape> */ + use SdkModel; + + /** @var list<string>|null $loginIDs */ + #[Optional('login_ids', list: 'string')] + public ?array $loginIDs; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<string>|null $loginIDs + */ + public static function with(?array $loginIDs = null): self + { + $self = new self; + + null !== $loginIDs && $self['loginIDs'] = $loginIDs; + + return $self; + } + + /** + * @param list<string> $loginIDs + */ + public function withLoginIDs(array $loginIDs): self + { + $self = clone $this; + $self['loginIDs'] = $loginIDs; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthLogoutParams.php b/src/Matrix/Bridges/Auth/AuthLogoutParams.php new file mode 100644 index 0000000..27b40aa --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthLogoutParams.php @@ -0,0 +1,68 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Log out of an existing login. + * + * @see BeeperDesktop\Services\Matrix\Bridges\AuthService::logout() + * + * @phpstan-type AuthLogoutParamsShape = array{bridgeID: string} + */ +final class AuthLogoutParams implements BaseModel +{ + /** @use SdkModel<AuthLogoutParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $bridgeID; + + /** + * `new AuthLogoutParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AuthLogoutParams::with(bridgeID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AuthLogoutParams)->withBridgeID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $bridgeID): self + { + $self = new self; + + $self['bridgeID'] = $bridgeID; + + return $self; + } + + public function withBridgeID(string $bridgeID): self + { + $self = clone $this; + $self['bridgeID'] = $bridgeID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginParams.php b/src/Matrix/Bridges/Auth/AuthStartLoginParams.php new file mode 100644 index 0000000..af73384 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginParams.php @@ -0,0 +1,106 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * 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. + * + * @see BeeperDesktop\Services\Matrix\Bridges\AuthService::startLogin() + * + * @phpstan-type AuthStartLoginParamsShape = array{ + * bridgeID: string, loginID?: string|null + * } + */ +final class AuthStartLoginParams implements BaseModel +{ + /** @use SdkModel<AuthStartLoginParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $bridgeID; + + /** + * 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. + */ + #[Optional] + public ?string $loginID; + + /** + * `new AuthStartLoginParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AuthStartLoginParams::with(bridgeID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AuthStartLoginParams)->withBridgeID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $bridgeID, ?string $loginID = null): self + { + $self = new self; + + $self['bridgeID'] = $bridgeID; + + null !== $loginID && $self['loginID'] = $loginID; + + return $self; + } + + public function withBridgeID(string $bridgeID): self + { + $self = clone $this; + $self['bridgeID'] = $bridgeID; + + return $self; + } + + /** + * 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. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse.php new file mode 100644 index 0000000..ee13195 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Concerns\SdkUnion; +use BeeperDesktop\Core\Conversion\Contracts\Converter; +use BeeperDesktop\Core\Conversion\Contracts\ConverterSource; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember3; + +/** + * A step in a login process. + * + * @phpstan-import-type UnionMember0Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0 + * @phpstan-import-type UnionMember1Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1 + * @phpstan-import-type UnionMember2Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2 + * @phpstan-import-type UnionMember3Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember3 + * + * @phpstan-type AuthStartLoginResponseVariants = UnionMember0|UnionMember1|UnionMember2|UnionMember3 + * @phpstan-type AuthStartLoginResponseShape = AuthStartLoginResponseVariants|UnionMember0Shape|UnionMember1Shape|UnionMember2Shape|UnionMember3Shape + */ +final class AuthStartLoginResponse implements ConverterSource +{ + use SdkUnion; + + /** + * @return list<string|Converter|ConverterSource>|array<string,string|Converter|ConverterSource> + */ + public static function variants(): array + { + return [ + UnionMember0::class, + UnionMember1::class, + UnionMember2::class, + UnionMember3::class, + ]; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0.php new file mode 100644 index 0000000..edfad01 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0.php @@ -0,0 +1,159 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0\DisplayAndWait; + +/** + * Display and wait login step. + * + * @phpstan-import-type DisplayAndWaitShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0\DisplayAndWait + * + * @phpstan-type UnionMember0Shape = array{ + * displayAndWait: DisplayAndWait|DisplayAndWaitShape, + * type: 'display_and_wait', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember0 implements BaseModel +{ + /** @use SdkModel<UnionMember0Shape> */ + use SdkModel; + + /** @var 'display_and_wait' $type */ + #[Required] + public string $type = 'display_and_wait'; + + /** + * Parameters for the display and wait login step. + */ + #[Required('display_and_wait')] + public DisplayAndWait $displayAndWait; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember0()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember0::with(displayAndWait: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember0)->withDisplayAndWait(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param DisplayAndWait|DisplayAndWaitShape $displayAndWait + */ + public static function with( + DisplayAndWait|array $displayAndWait, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['displayAndWait'] = $displayAndWait; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Parameters for the display and wait login step. + * + * @param DisplayAndWait|DisplayAndWaitShape $displayAndWait + */ + public function withDisplayAndWait( + DisplayAndWait|array $displayAndWait + ): self { + $self = clone $this; + $self['displayAndWait'] = $displayAndWait; + + return $self; + } + + /** + * @param 'display_and_wait' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0/DisplayAndWait.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0/DisplayAndWait.php new file mode 100644 index 0000000..2278efa --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0/DisplayAndWait.php @@ -0,0 +1,120 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0\DisplayAndWait\Type; + +/** + * Parameters for the display and wait login step. + * + * @phpstan-type DisplayAndWaitShape = array{ + * type: Type|value-of<Type>, data?: string|null, imageURL?: string|null + * } + */ +final class DisplayAndWait implements BaseModel +{ + /** @use SdkModel<DisplayAndWaitShape> */ + use SdkModel; + + /** + * The type of thing to display. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * The thing to display (raw data for QR, unicode emoji for emoji, plain string for code). + */ + #[Optional] + public ?string $data; + + /** + * 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. + */ + #[Optional('image_url')] + public ?string $imageURL; + + /** + * `new DisplayAndWait()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * DisplayAndWait::with(type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new DisplayAndWait)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + */ + public static function with( + Type|string $type, + ?string $data = null, + ?string $imageURL = null + ): self { + $self = new self; + + $self['type'] = $type; + + null !== $data && $self['data'] = $data; + null !== $imageURL && $self['imageURL'] = $imageURL; + + return $self; + } + + /** + * The type of thing to display. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * The thing to display (raw data for QR, unicode emoji for emoji, plain string for code). + */ + public function withData(string $data): self + { + $self = clone $this; + $self['data'] = $data; + + return $self; + } + + /** + * 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. + */ + public function withImageURL(string $imageURL): self + { + $self = clone $this; + $self['imageURL'] = $imageURL; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0/DisplayAndWait/Type.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0/DisplayAndWait/Type.php new file mode 100644 index 0000000..b08ab95 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember0/DisplayAndWait/Type.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0\DisplayAndWait; + +/** + * The type of thing to display. + */ +enum Type: string +{ + case QR = 'qr'; + + case EMOJI = 'emoji'; + + case CODE = 'code'; + + case NOTHING = 'nothing'; +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1.php new file mode 100644 index 0000000..a836ee9 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput; + +/** + * User input login step. + * + * @phpstan-import-type UserInputShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput + * + * @phpstan-type UnionMember1Shape = array{ + * type: 'user_input', + * userInput: UserInput|UserInputShape, + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember1 implements BaseModel +{ + /** @use SdkModel<UnionMember1Shape> */ + use SdkModel; + + /** @var 'user_input' $type */ + #[Required] + public string $type = 'user_input'; + + /** + * Parameters for the user input login step. + */ + #[Required('user_input')] + public UserInput $userInput; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember1()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember1::with(userInput: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember1)->withUserInput(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param UserInput|UserInputShape $userInput + */ + public static function with( + UserInput|array $userInput, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['userInput'] = $userInput; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * @param 'user_input' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Parameters for the user input login step. + * + * @param UserInput|UserInputShape $userInput + */ + public function withUserInput(UserInput|array $userInput): self + { + $self = clone $this; + $self['userInput'] = $userInput; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput.php new file mode 100644 index 0000000..c926fa2 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput.php @@ -0,0 +1,109 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Attachment; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Field; + +/** + * Parameters for the user input login step. + * + * @phpstan-import-type FieldShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Field + * @phpstan-import-type AttachmentShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Attachment + * + * @phpstan-type UserInputShape = array{ + * fields: list<Field|FieldShape>, + * attachments?: list<Attachment|AttachmentShape>|null, + * } + */ +final class UserInput implements BaseModel +{ + /** @use SdkModel<UserInputShape> */ + use SdkModel; + + /** + * The list of fields that the user is requested to fill. + * + * @var list<Field> $fields + */ + #[Required(list: Field::class)] + public array $fields; + + /** + * A list of media attachments to show the user alongside the form fields. + * + * @var list<Attachment>|null $attachments + */ + #[Optional(list: Attachment::class)] + public ?array $attachments; + + /** + * `new UserInput()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UserInput::with(fields: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UserInput)->withFields(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Field|FieldShape> $fields + * @param list<Attachment|AttachmentShape>|null $attachments + */ + public static function with(array $fields, ?array $attachments = null): self + { + $self = new self; + + $self['fields'] = $fields; + + null !== $attachments && $self['attachments'] = $attachments; + + return $self; + } + + /** + * The list of fields that the user is requested to fill. + * + * @param list<Field|FieldShape> $fields + */ + public function withFields(array $fields): self + { + $self = clone $this; + $self['fields'] = $fields; + + return $self; + } + + /** + * A list of media attachments to show the user alongside the form fields. + * + * @param list<Attachment|AttachmentShape> $attachments + */ + public function withAttachments(array $attachments): self + { + $self = clone $this; + $self['attachments'] = $attachments; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment.php new file mode 100644 index 0000000..467851a --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment.php @@ -0,0 +1,148 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Attachment\Info; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Attachment\Type; + +/** + * A media attachment to show the user. + * + * @phpstan-import-type InfoShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Attachment\Info + * + * @phpstan-type AttachmentShape = array{ + * content: string, + * filename: string, + * type: Type|value-of<Type>, + * info?: null|Info|InfoShape, + * } + */ +final class Attachment implements BaseModel +{ + /** @use SdkModel<AttachmentShape> */ + use SdkModel; + + /** + * The raw file content for the attachment encoded in base64. + */ + #[Required] + public string $content; + + /** + * The filename for the media attachment. + */ + #[Required] + public string $filename; + + /** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + */ + #[Optional] + public ?Info $info; + + /** + * `new Attachment()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Attachment::with(content: ..., filename: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Attachment)->withContent(...)->withFilename(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + * @param Info|InfoShape|null $info + */ + public static function with( + string $content, + string $filename, + Type|string $type, + Info|array|null $info = null, + ): self { + $self = new self; + + $self['content'] = $content; + $self['filename'] = $filename; + $self['type'] = $type; + + null !== $info && $self['info'] = $info; + + return $self; + } + + /** + * The raw file content for the attachment encoded in base64. + */ + public function withContent(string $content): self + { + $self = clone $this; + $self['content'] = $content; + + return $self; + } + + /** + * The filename for the media attachment. + */ + public function withFilename(string $filename): self + { + $self = clone $this; + $self['filename'] = $filename; + + return $self; + } + + /** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + * + * @param Info|InfoShape $info + */ + public function withInfo(Info|array $info): self + { + $self = clone $this; + $self['info'] = $info; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment/Info.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment/Info.php new file mode 100644 index 0000000..49da65a --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment/Info.php @@ -0,0 +1,116 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Attachment; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + * + * @phpstan-type InfoShape = array{ + * h?: float|null, mimetype?: string|null, size?: float|null, w?: float|null + * } + */ +final class Info implements BaseModel +{ + /** @use SdkModel<InfoShape> */ + use SdkModel; + + /** + * The height of the media in pixels. Only applicable for images and videos. + */ + #[Optional] + public ?float $h; + + /** + * The MIME type for the media content. + */ + #[Optional] + public ?string $mimetype; + + /** + * The size of the media content in number of bytes. Strongly recommended to include. + */ + #[Optional] + public ?float $size; + + /** + * The width of the media in pixels. Only applicable for images and videos. + */ + #[Optional] + public ?float $w; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?float $h = null, + ?string $mimetype = null, + ?float $size = null, + ?float $w = null, + ): self { + $self = new self; + + null !== $h && $self['h'] = $h; + null !== $mimetype && $self['mimetype'] = $mimetype; + null !== $size && $self['size'] = $size; + null !== $w && $self['w'] = $w; + + return $self; + } + + /** + * The height of the media in pixels. Only applicable for images and videos. + */ + public function withH(float $h): self + { + $self = clone $this; + $self['h'] = $h; + + return $self; + } + + /** + * The MIME type for the media content. + */ + public function withMimetype(string $mimetype): self + { + $self = clone $this; + $self['mimetype'] = $mimetype; + + return $self; + } + + /** + * The size of the media content in number of bytes. Strongly recommended to include. + */ + public function withSize(float $size): self + { + $self = clone $this; + $self['size'] = $size; + + return $self; + } + + /** + * The width of the media in pixels. Only applicable for images and videos. + */ + public function withW(float $w): self + { + $self = clone $this; + $self['w'] = $w; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment/Type.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment/Type.php new file mode 100644 index 0000000..c11885b --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Attachment/Type.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Attachment; + +/** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + */ +enum Type: string +{ + case M_IMAGE = 'm.image'; + + case M_AUDIO = 'm.audio'; +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Field.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Field.php new file mode 100644 index 0000000..9652ab2 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Field.php @@ -0,0 +1,207 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Field\Type; + +/** + * A field that the user can fill. + * + * @phpstan-type FieldShape = array{ + * id: string, + * name: string, + * type: Type|value-of<Type>, + * defaultValue?: string|null, + * description?: string|null, + * options?: list<string>|null, + * pattern?: string|null, + * } + */ +final class Field implements BaseModel +{ + /** @use SdkModel<FieldShape> */ + use SdkModel; + + /** + * The internal ID of the field. This must be used as the key in the object when submitting the data back to the bridge. + */ + #[Required] + public string $id; + + /** + * The name of the field shown to the user. + */ + #[Required] + public string $name; + + /** + * The type of field. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * A default value that the client can pre-fill the field with. + */ + #[Optional('default_value')] + public ?string $defaultValue; + + /** + * A more detailed description of the field shown to the user. + */ + #[Optional] + public ?string $description; + + /** + * For fields of type select, the valid options. + * + * @var list<string>|null $options + */ + #[Optional(list: 'string')] + public ?array $options; + + /** + * A regular expression that the field value must match. + */ + #[Optional] + public ?string $pattern; + + /** + * `new Field()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Field::with(id: ..., name: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Field)->withID(...)->withName(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + * @param list<string>|null $options + */ + public static function with( + string $id, + string $name, + Type|string $type, + ?string $defaultValue = null, + ?string $description = null, + ?array $options = null, + ?string $pattern = null, + ): self { + $self = new self; + + $self['id'] = $id; + $self['name'] = $name; + $self['type'] = $type; + + null !== $defaultValue && $self['defaultValue'] = $defaultValue; + null !== $description && $self['description'] = $description; + null !== $options && $self['options'] = $options; + null !== $pattern && $self['pattern'] = $pattern; + + return $self; + } + + /** + * The internal ID of the field. This must be used as the key in the object when submitting the data back to the bridge. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * The name of the field shown to the user. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The type of field. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * A default value that the client can pre-fill the field with. + */ + public function withDefaultValue(string $defaultValue): self + { + $self = clone $this; + $self['defaultValue'] = $defaultValue; + + return $self; + } + + /** + * A more detailed description of the field shown to the user. + */ + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * For fields of type select, the valid options. + * + * @param list<string> $options + */ + public function withOptions(array $options): self + { + $self = clone $this; + $self['options'] = $options; + + return $self; + } + + /** + * A regular expression that the field value must match. + */ + public function withPattern(string $pattern): self + { + $self = clone $this; + $self['pattern'] = $pattern; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Field/Type.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Field/Type.php new file mode 100644 index 0000000..2586744 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember1/UserInput/Field/Type.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1\UserInput\Field; + +/** + * The type of field. + */ +enum Type: string +{ + case USERNAME = 'username'; + + case PHONE_NUMBER = 'phone_number'; + + case EMAIL = 'email'; + + case PASSWORD = 'password'; + + case _2FA_CODE = '2fa_code'; + + case TOKEN = 'token'; + + case URL = 'url'; + + case DOMAIN = 'domain'; + + case SELECT = 'select'; +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2.php new file mode 100644 index 0000000..4156c73 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2\Cookies; + +/** + * Cookie login step. + * + * @phpstan-import-type CookiesShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2\Cookies + * + * @phpstan-type UnionMember2Shape = array{ + * cookies: Cookies|CookiesShape, + * type: 'cookies', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember2 implements BaseModel +{ + /** @use SdkModel<UnionMember2Shape> */ + use SdkModel; + + /** @var 'cookies' $type */ + #[Required] + public string $type = 'cookies'; + + /** + * Parameters for the cookie login step. + */ + #[Required] + public Cookies $cookies; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember2()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember2::with(cookies: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember2)->withCookies(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Cookies|CookiesShape $cookies + */ + public static function with( + Cookies|array $cookies, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['cookies'] = $cookies; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Parameters for the cookie login step. + * + * @param Cookies|CookiesShape $cookies + */ + public function withCookies(Cookies|array $cookies): self + { + $self = clone $this; + $self['cookies'] = $cookies; + + return $self; + } + + /** + * @param 'cookies' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies.php new file mode 100644 index 0000000..3065e36 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies.php @@ -0,0 +1,176 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2\Cookies\Field; + +/** + * Parameters for the cookie login step. + * + * @phpstan-import-type FieldShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2\Cookies\Field + * + * @phpstan-type CookiesShape = array{ + * fields: list<Field|FieldShape>, + * url: string, + * extractJs?: string|null, + * userAgent?: string|null, + * waitForURLPattern?: string|null, + * } + */ +final class Cookies implements BaseModel +{ + /** @use SdkModel<CookiesShape> */ + use SdkModel; + + /** + * The list of cookies or other stored data that must be extracted. + * + * @var list<Field> $fields + */ + #[Required(list: Field::class)] + public array $fields; + + /** + * The URL to open when using a webview to extract cookies. + */ + #[Required] + public string $url; + + /** + * 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. + */ + #[Optional('extract_js')] + public ?string $extractJs; + + /** + * An optional user agent that the webview should use. + */ + #[Optional('user_agent')] + public ?string $userAgent; + + /** + * 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. + */ + #[Optional('wait_for_url_pattern')] + public ?string $waitForURLPattern; + + /** + * `new Cookies()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Cookies::with(fields: ..., url: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Cookies)->withFields(...)->withURL(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Field|FieldShape> $fields + */ + public static function with( + array $fields, + string $url, + ?string $extractJs = null, + ?string $userAgent = null, + ?string $waitForURLPattern = null, + ): self { + $self = new self; + + $self['fields'] = $fields; + $self['url'] = $url; + + null !== $extractJs && $self['extractJs'] = $extractJs; + null !== $userAgent && $self['userAgent'] = $userAgent; + null !== $waitForURLPattern && $self['waitForURLPattern'] = $waitForURLPattern; + + return $self; + } + + /** + * The list of cookies or other stored data that must be extracted. + * + * @param list<Field|FieldShape> $fields + */ + public function withFields(array $fields): self + { + $self = clone $this; + $self['fields'] = $fields; + + return $self; + } + + /** + * The URL to open when using a webview to extract cookies. + */ + public function withURL(string $url): self + { + $self = clone $this; + $self['url'] = $url; + + return $self; + } + + /** + * 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. + */ + public function withExtractJs(string $extractJs): self + { + $self = clone $this; + $self['extractJs'] = $extractJs; + + return $self; + } + + /** + * An optional user agent that the webview should use. + */ + public function withUserAgent(string $userAgent): self + { + $self = clone $this; + $self['userAgent'] = $userAgent; + + return $self; + } + + /** + * 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. + */ + public function withWaitForURLPattern(string $waitForURLPattern): self + { + $self = clone $this; + $self['waitForURLPattern'] = $waitForURLPattern; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies/Field.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies/Field.php new file mode 100644 index 0000000..fd11892 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies/Field.php @@ -0,0 +1,142 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2\Cookies; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2\Cookies\Field\Type; + +/** + * An individual cookie or other stored data item that must be extracted. + * + * @phpstan-type FieldShape = array{ + * name: string, + * type: Type|value-of<Type>, + * cookieDomain?: string|null, + * requestURLRegex?: string|null, + * } + */ +final class Field implements BaseModel +{ + /** @use SdkModel<FieldShape> */ + use SdkModel; + + /** + * The name of the item to extract. + */ + #[Required] + public string $name; + + /** + * The type of data to extract. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * For the `cookie` type, the domain of the cookie. + */ + #[Optional('cookie_domain')] + public ?string $cookieDomain; + + /** + * For the `request_header` and `request_body` types, a regex that matches the URLs from which the values can be extracted. + */ + #[Optional('request_url_regex')] + public ?string $requestURLRegex; + + /** + * `new Field()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Field::with(name: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Field)->withName(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + */ + public static function with( + string $name, + Type|string $type, + ?string $cookieDomain = null, + ?string $requestURLRegex = null, + ): self { + $self = new self; + + $self['name'] = $name; + $self['type'] = $type; + + null !== $cookieDomain && $self['cookieDomain'] = $cookieDomain; + null !== $requestURLRegex && $self['requestURLRegex'] = $requestURLRegex; + + return $self; + } + + /** + * The name of the item to extract. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The type of data to extract. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * For the `cookie` type, the domain of the cookie. + */ + public function withCookieDomain(string $cookieDomain): self + { + $self = clone $this; + $self['cookieDomain'] = $cookieDomain; + + return $self; + } + + /** + * For the `request_header` and `request_body` types, a regex that matches the URLs from which the values can be extracted. + */ + public function withRequestURLRegex(string $requestURLRegex): self + { + $self = clone $this; + $self['requestURLRegex'] = $requestURLRegex; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies/Field/Type.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies/Field/Type.php new file mode 100644 index 0000000..4ea4b9c --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember2/Cookies/Field/Type.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2\Cookies\Field; + +/** + * The type of data to extract. + */ +enum Type: string +{ + case COOKIE = 'cookie'; + + case LOCAL_STORAGE = 'local_storage'; + + case REQUEST_HEADER = 'request_header'; + + case REQUEST_BODY = 'request_body'; + + case SPECIAL = 'special'; +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember3.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember3.php new file mode 100644 index 0000000..a6bff9d --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember3.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember3\Complete; + +/** + * Login complete. + * + * @phpstan-import-type CompleteShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember3\Complete + * + * @phpstan-type UnionMember3Shape = array{ + * complete: Complete|CompleteShape, + * type: 'complete', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember3 implements BaseModel +{ + /** @use SdkModel<UnionMember3Shape> */ + use SdkModel; + + /** @var 'complete' $type */ + #[Required] + public string $type = 'complete'; + + /** + * Information about the completed login. + */ + #[Required] + public Complete $complete; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember3()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember3::with(complete: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember3)->withComplete(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Complete|CompleteShape $complete + */ + public static function with( + Complete|array $complete, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['complete'] = $complete; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Information about the completed login. + * + * @param Complete|CompleteShape $complete + */ + public function withComplete(Complete|array $complete): self + { + $self = clone $this; + $self['complete'] = $complete; + + return $self; + } + + /** + * @param 'complete' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember3/Complete.php b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember3/Complete.php new file mode 100644 index 0000000..c00c285 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthStartLoginResponse/UnionMember3/Complete.php @@ -0,0 +1,56 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember3; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Information about the completed login. + * + * @phpstan-type CompleteShape = array{userLoginID?: string|null} + */ +final class Complete implements BaseModel +{ + /** @use SdkModel<CompleteShape> */ + use SdkModel; + + /** + * The unique ID of a login. Defined by the network connector. + */ + #[Optional('user_login_id')] + public ?string $userLoginID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $userLoginID = null): self + { + $self = new self; + + null !== $userLoginID && $self['userLoginID'] = $userLoginID; + + return $self; + } + + /** + * The unique ID of a login. Defined by the network connector. + */ + public function withUserLoginID(string $userLoginID): self + { + $self = clone $this; + $self['userLoginID'] = $userLoginID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesParams.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesParams.php new file mode 100644 index 0000000..3bcac60 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesParams.php @@ -0,0 +1,106 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Submit extracted cookies in a login process. + * + * @see BeeperDesktop\Services\Matrix\Bridges\AuthService::submitCookies() + * + * @phpstan-type AuthSubmitCookiesParamsShape = array{ + * bridgeID: string, loginProcessID: string, body: array<string,string> + * } + */ +final class AuthSubmitCookiesParams implements BaseModel +{ + /** @use SdkModel<AuthSubmitCookiesParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $bridgeID; + + #[Required] + public string $loginProcessID; + + /** @var array<string,string> $body */ + #[Required(map: 'string')] + public array $body; + + /** + * `new AuthSubmitCookiesParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AuthSubmitCookiesParams::with(bridgeID: ..., loginProcessID: ..., body: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AuthSubmitCookiesParams) + * ->withBridgeID(...) + * ->withLoginProcessID(...) + * ->withBody(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param array<string,string> $body + */ + public static function with( + string $bridgeID, + string $loginProcessID, + array $body + ): self { + $self = new self; + + $self['bridgeID'] = $bridgeID; + $self['loginProcessID'] = $loginProcessID; + $self['body'] = $body; + + return $self; + } + + public function withBridgeID(string $bridgeID): self + { + $self = clone $this; + $self['bridgeID'] = $bridgeID; + + return $self; + } + + public function withLoginProcessID(string $loginProcessID): self + { + $self = clone $this; + $self['loginProcessID'] = $loginProcessID; + + return $self; + } + + /** + * @param array<string,string> $body + */ + public function withBody(array $body): self + { + $self = clone $this; + $self['body'] = $body; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse.php new file mode 100644 index 0000000..514e882 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Concerns\SdkUnion; +use BeeperDesktop\Core\Conversion\Contracts\Converter; +use BeeperDesktop\Core\Conversion\Contracts\ConverterSource; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember3; + +/** + * A step in a login process. + * + * @phpstan-import-type UnionMember0Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0 + * @phpstan-import-type UnionMember1Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1 + * @phpstan-import-type UnionMember2Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2 + * @phpstan-import-type UnionMember3Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember3 + * + * @phpstan-type AuthSubmitCookiesResponseVariants = UnionMember0|UnionMember1|UnionMember2|UnionMember3 + * @phpstan-type AuthSubmitCookiesResponseShape = AuthSubmitCookiesResponseVariants|UnionMember0Shape|UnionMember1Shape|UnionMember2Shape|UnionMember3Shape + */ +final class AuthSubmitCookiesResponse implements ConverterSource +{ + use SdkUnion; + + /** + * @return list<string|Converter|ConverterSource>|array<string,string|Converter|ConverterSource> + */ + public static function variants(): array + { + return [ + UnionMember0::class, + UnionMember1::class, + UnionMember2::class, + UnionMember3::class, + ]; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0.php new file mode 100644 index 0000000..28acd40 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0.php @@ -0,0 +1,159 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0\DisplayAndWait; + +/** + * Display and wait login step. + * + * @phpstan-import-type DisplayAndWaitShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0\DisplayAndWait + * + * @phpstan-type UnionMember0Shape = array{ + * displayAndWait: DisplayAndWait|DisplayAndWaitShape, + * type: 'display_and_wait', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember0 implements BaseModel +{ + /** @use SdkModel<UnionMember0Shape> */ + use SdkModel; + + /** @var 'display_and_wait' $type */ + #[Required] + public string $type = 'display_and_wait'; + + /** + * Parameters for the display and wait login step. + */ + #[Required('display_and_wait')] + public DisplayAndWait $displayAndWait; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember0()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember0::with(displayAndWait: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember0)->withDisplayAndWait(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param DisplayAndWait|DisplayAndWaitShape $displayAndWait + */ + public static function with( + DisplayAndWait|array $displayAndWait, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['displayAndWait'] = $displayAndWait; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Parameters for the display and wait login step. + * + * @param DisplayAndWait|DisplayAndWaitShape $displayAndWait + */ + public function withDisplayAndWait( + DisplayAndWait|array $displayAndWait + ): self { + $self = clone $this; + $self['displayAndWait'] = $displayAndWait; + + return $self; + } + + /** + * @param 'display_and_wait' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0/DisplayAndWait.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0/DisplayAndWait.php new file mode 100644 index 0000000..d797a4c --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0/DisplayAndWait.php @@ -0,0 +1,120 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0\DisplayAndWait\Type; + +/** + * Parameters for the display and wait login step. + * + * @phpstan-type DisplayAndWaitShape = array{ + * type: Type|value-of<Type>, data?: string|null, imageURL?: string|null + * } + */ +final class DisplayAndWait implements BaseModel +{ + /** @use SdkModel<DisplayAndWaitShape> */ + use SdkModel; + + /** + * The type of thing to display. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * The thing to display (raw data for QR, unicode emoji for emoji, plain string for code). + */ + #[Optional] + public ?string $data; + + /** + * 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. + */ + #[Optional('image_url')] + public ?string $imageURL; + + /** + * `new DisplayAndWait()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * DisplayAndWait::with(type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new DisplayAndWait)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + */ + public static function with( + Type|string $type, + ?string $data = null, + ?string $imageURL = null + ): self { + $self = new self; + + $self['type'] = $type; + + null !== $data && $self['data'] = $data; + null !== $imageURL && $self['imageURL'] = $imageURL; + + return $self; + } + + /** + * The type of thing to display. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * The thing to display (raw data for QR, unicode emoji for emoji, plain string for code). + */ + public function withData(string $data): self + { + $self = clone $this; + $self['data'] = $data; + + return $self; + } + + /** + * 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. + */ + public function withImageURL(string $imageURL): self + { + $self = clone $this; + $self['imageURL'] = $imageURL; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0/DisplayAndWait/Type.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0/DisplayAndWait/Type.php new file mode 100644 index 0000000..518d0e1 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember0/DisplayAndWait/Type.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0\DisplayAndWait; + +/** + * The type of thing to display. + */ +enum Type: string +{ + case QR = 'qr'; + + case EMOJI = 'emoji'; + + case CODE = 'code'; + + case NOTHING = 'nothing'; +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1.php new file mode 100644 index 0000000..2e236b2 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput; + +/** + * User input login step. + * + * @phpstan-import-type UserInputShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput + * + * @phpstan-type UnionMember1Shape = array{ + * type: 'user_input', + * userInput: UserInput|UserInputShape, + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember1 implements BaseModel +{ + /** @use SdkModel<UnionMember1Shape> */ + use SdkModel; + + /** @var 'user_input' $type */ + #[Required] + public string $type = 'user_input'; + + /** + * Parameters for the user input login step. + */ + #[Required('user_input')] + public UserInput $userInput; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember1()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember1::with(userInput: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember1)->withUserInput(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param UserInput|UserInputShape $userInput + */ + public static function with( + UserInput|array $userInput, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['userInput'] = $userInput; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * @param 'user_input' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Parameters for the user input login step. + * + * @param UserInput|UserInputShape $userInput + */ + public function withUserInput(UserInput|array $userInput): self + { + $self = clone $this; + $self['userInput'] = $userInput; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput.php new file mode 100644 index 0000000..b12b33a --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput.php @@ -0,0 +1,109 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Attachment; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Field; + +/** + * Parameters for the user input login step. + * + * @phpstan-import-type FieldShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Field + * @phpstan-import-type AttachmentShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Attachment + * + * @phpstan-type UserInputShape = array{ + * fields: list<Field|FieldShape>, + * attachments?: list<Attachment|AttachmentShape>|null, + * } + */ +final class UserInput implements BaseModel +{ + /** @use SdkModel<UserInputShape> */ + use SdkModel; + + /** + * The list of fields that the user is requested to fill. + * + * @var list<Field> $fields + */ + #[Required(list: Field::class)] + public array $fields; + + /** + * A list of media attachments to show the user alongside the form fields. + * + * @var list<Attachment>|null $attachments + */ + #[Optional(list: Attachment::class)] + public ?array $attachments; + + /** + * `new UserInput()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UserInput::with(fields: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UserInput)->withFields(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Field|FieldShape> $fields + * @param list<Attachment|AttachmentShape>|null $attachments + */ + public static function with(array $fields, ?array $attachments = null): self + { + $self = new self; + + $self['fields'] = $fields; + + null !== $attachments && $self['attachments'] = $attachments; + + return $self; + } + + /** + * The list of fields that the user is requested to fill. + * + * @param list<Field|FieldShape> $fields + */ + public function withFields(array $fields): self + { + $self = clone $this; + $self['fields'] = $fields; + + return $self; + } + + /** + * A list of media attachments to show the user alongside the form fields. + * + * @param list<Attachment|AttachmentShape> $attachments + */ + public function withAttachments(array $attachments): self + { + $self = clone $this; + $self['attachments'] = $attachments; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment.php new file mode 100644 index 0000000..3ee65a1 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment.php @@ -0,0 +1,148 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Attachment\Info; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Attachment\Type; + +/** + * A media attachment to show the user. + * + * @phpstan-import-type InfoShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Attachment\Info + * + * @phpstan-type AttachmentShape = array{ + * content: string, + * filename: string, + * type: Type|value-of<Type>, + * info?: null|Info|InfoShape, + * } + */ +final class Attachment implements BaseModel +{ + /** @use SdkModel<AttachmentShape> */ + use SdkModel; + + /** + * The raw file content for the attachment encoded in base64. + */ + #[Required] + public string $content; + + /** + * The filename for the media attachment. + */ + #[Required] + public string $filename; + + /** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + */ + #[Optional] + public ?Info $info; + + /** + * `new Attachment()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Attachment::with(content: ..., filename: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Attachment)->withContent(...)->withFilename(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + * @param Info|InfoShape|null $info + */ + public static function with( + string $content, + string $filename, + Type|string $type, + Info|array|null $info = null, + ): self { + $self = new self; + + $self['content'] = $content; + $self['filename'] = $filename; + $self['type'] = $type; + + null !== $info && $self['info'] = $info; + + return $self; + } + + /** + * The raw file content for the attachment encoded in base64. + */ + public function withContent(string $content): self + { + $self = clone $this; + $self['content'] = $content; + + return $self; + } + + /** + * The filename for the media attachment. + */ + public function withFilename(string $filename): self + { + $self = clone $this; + $self['filename'] = $filename; + + return $self; + } + + /** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + * + * @param Info|InfoShape $info + */ + public function withInfo(Info|array $info): self + { + $self = clone $this; + $self['info'] = $info; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment/Info.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment/Info.php new file mode 100644 index 0000000..584a62e --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment/Info.php @@ -0,0 +1,116 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Attachment; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + * + * @phpstan-type InfoShape = array{ + * h?: float|null, mimetype?: string|null, size?: float|null, w?: float|null + * } + */ +final class Info implements BaseModel +{ + /** @use SdkModel<InfoShape> */ + use SdkModel; + + /** + * The height of the media in pixels. Only applicable for images and videos. + */ + #[Optional] + public ?float $h; + + /** + * The MIME type for the media content. + */ + #[Optional] + public ?string $mimetype; + + /** + * The size of the media content in number of bytes. Strongly recommended to include. + */ + #[Optional] + public ?float $size; + + /** + * The width of the media in pixels. Only applicable for images and videos. + */ + #[Optional] + public ?float $w; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?float $h = null, + ?string $mimetype = null, + ?float $size = null, + ?float $w = null, + ): self { + $self = new self; + + null !== $h && $self['h'] = $h; + null !== $mimetype && $self['mimetype'] = $mimetype; + null !== $size && $self['size'] = $size; + null !== $w && $self['w'] = $w; + + return $self; + } + + /** + * The height of the media in pixels. Only applicable for images and videos. + */ + public function withH(float $h): self + { + $self = clone $this; + $self['h'] = $h; + + return $self; + } + + /** + * The MIME type for the media content. + */ + public function withMimetype(string $mimetype): self + { + $self = clone $this; + $self['mimetype'] = $mimetype; + + return $self; + } + + /** + * The size of the media content in number of bytes. Strongly recommended to include. + */ + public function withSize(float $size): self + { + $self = clone $this; + $self['size'] = $size; + + return $self; + } + + /** + * The width of the media in pixels. Only applicable for images and videos. + */ + public function withW(float $w): self + { + $self = clone $this; + $self['w'] = $w; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment/Type.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment/Type.php new file mode 100644 index 0000000..876c2ee --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Attachment/Type.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Attachment; + +/** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + */ +enum Type: string +{ + case M_IMAGE = 'm.image'; + + case M_AUDIO = 'm.audio'; +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Field.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Field.php new file mode 100644 index 0000000..56d284c --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Field.php @@ -0,0 +1,207 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Field\Type; + +/** + * A field that the user can fill. + * + * @phpstan-type FieldShape = array{ + * id: string, + * name: string, + * type: Type|value-of<Type>, + * defaultValue?: string|null, + * description?: string|null, + * options?: list<string>|null, + * pattern?: string|null, + * } + */ +final class Field implements BaseModel +{ + /** @use SdkModel<FieldShape> */ + use SdkModel; + + /** + * The internal ID of the field. This must be used as the key in the object when submitting the data back to the bridge. + */ + #[Required] + public string $id; + + /** + * The name of the field shown to the user. + */ + #[Required] + public string $name; + + /** + * The type of field. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * A default value that the client can pre-fill the field with. + */ + #[Optional('default_value')] + public ?string $defaultValue; + + /** + * A more detailed description of the field shown to the user. + */ + #[Optional] + public ?string $description; + + /** + * For fields of type select, the valid options. + * + * @var list<string>|null $options + */ + #[Optional(list: 'string')] + public ?array $options; + + /** + * A regular expression that the field value must match. + */ + #[Optional] + public ?string $pattern; + + /** + * `new Field()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Field::with(id: ..., name: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Field)->withID(...)->withName(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + * @param list<string>|null $options + */ + public static function with( + string $id, + string $name, + Type|string $type, + ?string $defaultValue = null, + ?string $description = null, + ?array $options = null, + ?string $pattern = null, + ): self { + $self = new self; + + $self['id'] = $id; + $self['name'] = $name; + $self['type'] = $type; + + null !== $defaultValue && $self['defaultValue'] = $defaultValue; + null !== $description && $self['description'] = $description; + null !== $options && $self['options'] = $options; + null !== $pattern && $self['pattern'] = $pattern; + + return $self; + } + + /** + * The internal ID of the field. This must be used as the key in the object when submitting the data back to the bridge. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * The name of the field shown to the user. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The type of field. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * A default value that the client can pre-fill the field with. + */ + public function withDefaultValue(string $defaultValue): self + { + $self = clone $this; + $self['defaultValue'] = $defaultValue; + + return $self; + } + + /** + * A more detailed description of the field shown to the user. + */ + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * For fields of type select, the valid options. + * + * @param list<string> $options + */ + public function withOptions(array $options): self + { + $self = clone $this; + $self['options'] = $options; + + return $self; + } + + /** + * A regular expression that the field value must match. + */ + public function withPattern(string $pattern): self + { + $self = clone $this; + $self['pattern'] = $pattern; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Field/Type.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Field/Type.php new file mode 100644 index 0000000..54915fd --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember1/UserInput/Field/Type.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1\UserInput\Field; + +/** + * The type of field. + */ +enum Type: string +{ + case USERNAME = 'username'; + + case PHONE_NUMBER = 'phone_number'; + + case EMAIL = 'email'; + + case PASSWORD = 'password'; + + case _2FA_CODE = '2fa_code'; + + case TOKEN = 'token'; + + case URL = 'url'; + + case DOMAIN = 'domain'; + + case SELECT = 'select'; +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2.php new file mode 100644 index 0000000..27db0e6 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2\Cookies; + +/** + * Cookie login step. + * + * @phpstan-import-type CookiesShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2\Cookies + * + * @phpstan-type UnionMember2Shape = array{ + * cookies: Cookies|CookiesShape, + * type: 'cookies', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember2 implements BaseModel +{ + /** @use SdkModel<UnionMember2Shape> */ + use SdkModel; + + /** @var 'cookies' $type */ + #[Required] + public string $type = 'cookies'; + + /** + * Parameters for the cookie login step. + */ + #[Required] + public Cookies $cookies; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember2()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember2::with(cookies: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember2)->withCookies(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Cookies|CookiesShape $cookies + */ + public static function with( + Cookies|array $cookies, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['cookies'] = $cookies; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Parameters for the cookie login step. + * + * @param Cookies|CookiesShape $cookies + */ + public function withCookies(Cookies|array $cookies): self + { + $self = clone $this; + $self['cookies'] = $cookies; + + return $self; + } + + /** + * @param 'cookies' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies.php new file mode 100644 index 0000000..213ae67 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies.php @@ -0,0 +1,176 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2\Cookies\Field; + +/** + * Parameters for the cookie login step. + * + * @phpstan-import-type FieldShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2\Cookies\Field + * + * @phpstan-type CookiesShape = array{ + * fields: list<Field|FieldShape>, + * url: string, + * extractJs?: string|null, + * userAgent?: string|null, + * waitForURLPattern?: string|null, + * } + */ +final class Cookies implements BaseModel +{ + /** @use SdkModel<CookiesShape> */ + use SdkModel; + + /** + * The list of cookies or other stored data that must be extracted. + * + * @var list<Field> $fields + */ + #[Required(list: Field::class)] + public array $fields; + + /** + * The URL to open when using a webview to extract cookies. + */ + #[Required] + public string $url; + + /** + * 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. + */ + #[Optional('extract_js')] + public ?string $extractJs; + + /** + * An optional user agent that the webview should use. + */ + #[Optional('user_agent')] + public ?string $userAgent; + + /** + * 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. + */ + #[Optional('wait_for_url_pattern')] + public ?string $waitForURLPattern; + + /** + * `new Cookies()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Cookies::with(fields: ..., url: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Cookies)->withFields(...)->withURL(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Field|FieldShape> $fields + */ + public static function with( + array $fields, + string $url, + ?string $extractJs = null, + ?string $userAgent = null, + ?string $waitForURLPattern = null, + ): self { + $self = new self; + + $self['fields'] = $fields; + $self['url'] = $url; + + null !== $extractJs && $self['extractJs'] = $extractJs; + null !== $userAgent && $self['userAgent'] = $userAgent; + null !== $waitForURLPattern && $self['waitForURLPattern'] = $waitForURLPattern; + + return $self; + } + + /** + * The list of cookies or other stored data that must be extracted. + * + * @param list<Field|FieldShape> $fields + */ + public function withFields(array $fields): self + { + $self = clone $this; + $self['fields'] = $fields; + + return $self; + } + + /** + * The URL to open when using a webview to extract cookies. + */ + public function withURL(string $url): self + { + $self = clone $this; + $self['url'] = $url; + + return $self; + } + + /** + * 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. + */ + public function withExtractJs(string $extractJs): self + { + $self = clone $this; + $self['extractJs'] = $extractJs; + + return $self; + } + + /** + * An optional user agent that the webview should use. + */ + public function withUserAgent(string $userAgent): self + { + $self = clone $this; + $self['userAgent'] = $userAgent; + + return $self; + } + + /** + * 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. + */ + public function withWaitForURLPattern(string $waitForURLPattern): self + { + $self = clone $this; + $self['waitForURLPattern'] = $waitForURLPattern; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies/Field.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies/Field.php new file mode 100644 index 0000000..6873aef --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies/Field.php @@ -0,0 +1,142 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2\Cookies; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2\Cookies\Field\Type; + +/** + * An individual cookie or other stored data item that must be extracted. + * + * @phpstan-type FieldShape = array{ + * name: string, + * type: Type|value-of<Type>, + * cookieDomain?: string|null, + * requestURLRegex?: string|null, + * } + */ +final class Field implements BaseModel +{ + /** @use SdkModel<FieldShape> */ + use SdkModel; + + /** + * The name of the item to extract. + */ + #[Required] + public string $name; + + /** + * The type of data to extract. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * For the `cookie` type, the domain of the cookie. + */ + #[Optional('cookie_domain')] + public ?string $cookieDomain; + + /** + * For the `request_header` and `request_body` types, a regex that matches the URLs from which the values can be extracted. + */ + #[Optional('request_url_regex')] + public ?string $requestURLRegex; + + /** + * `new Field()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Field::with(name: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Field)->withName(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + */ + public static function with( + string $name, + Type|string $type, + ?string $cookieDomain = null, + ?string $requestURLRegex = null, + ): self { + $self = new self; + + $self['name'] = $name; + $self['type'] = $type; + + null !== $cookieDomain && $self['cookieDomain'] = $cookieDomain; + null !== $requestURLRegex && $self['requestURLRegex'] = $requestURLRegex; + + return $self; + } + + /** + * The name of the item to extract. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The type of data to extract. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * For the `cookie` type, the domain of the cookie. + */ + public function withCookieDomain(string $cookieDomain): self + { + $self = clone $this; + $self['cookieDomain'] = $cookieDomain; + + return $self; + } + + /** + * For the `request_header` and `request_body` types, a regex that matches the URLs from which the values can be extracted. + */ + public function withRequestURLRegex(string $requestURLRegex): self + { + $self = clone $this; + $self['requestURLRegex'] = $requestURLRegex; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies/Field/Type.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies/Field/Type.php new file mode 100644 index 0000000..2878a8a --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember2/Cookies/Field/Type.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2\Cookies\Field; + +/** + * The type of data to extract. + */ +enum Type: string +{ + case COOKIE = 'cookie'; + + case LOCAL_STORAGE = 'local_storage'; + + case REQUEST_HEADER = 'request_header'; + + case REQUEST_BODY = 'request_body'; + + case SPECIAL = 'special'; +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember3.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember3.php new file mode 100644 index 0000000..e3233a7 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember3.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember3\Complete; + +/** + * Login complete. + * + * @phpstan-import-type CompleteShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember3\Complete + * + * @phpstan-type UnionMember3Shape = array{ + * complete: Complete|CompleteShape, + * type: 'complete', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember3 implements BaseModel +{ + /** @use SdkModel<UnionMember3Shape> */ + use SdkModel; + + /** @var 'complete' $type */ + #[Required] + public string $type = 'complete'; + + /** + * Information about the completed login. + */ + #[Required] + public Complete $complete; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember3()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember3::with(complete: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember3)->withComplete(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Complete|CompleteShape $complete + */ + public static function with( + Complete|array $complete, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['complete'] = $complete; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Information about the completed login. + * + * @param Complete|CompleteShape $complete + */ + public function withComplete(Complete|array $complete): self + { + $self = clone $this; + $self['complete'] = $complete; + + return $self; + } + + /** + * @param 'complete' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember3/Complete.php b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember3/Complete.php new file mode 100644 index 0000000..41ce3de --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitCookiesResponse/UnionMember3/Complete.php @@ -0,0 +1,56 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember3; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Information about the completed login. + * + * @phpstan-type CompleteShape = array{userLoginID?: string|null} + */ +final class Complete implements BaseModel +{ + /** @use SdkModel<CompleteShape> */ + use SdkModel; + + /** + * The unique ID of a login. Defined by the network connector. + */ + #[Optional('user_login_id')] + public ?string $userLoginID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $userLoginID = null): self + { + $self = new self; + + null !== $userLoginID && $self['userLoginID'] = $userLoginID; + + return $self; + } + + /** + * The unique ID of a login. Defined by the network connector. + */ + public function withUserLoginID(string $userLoginID): self + { + $self = clone $this; + $self['userLoginID'] = $userLoginID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputParams.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputParams.php new file mode 100644 index 0000000..2d6ee3b --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputParams.php @@ -0,0 +1,106 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Submit user input in a login process. + * + * @see BeeperDesktop\Services\Matrix\Bridges\AuthService::submitUserInput() + * + * @phpstan-type AuthSubmitUserInputParamsShape = array{ + * bridgeID: string, loginProcessID: string, body: array<string,string> + * } + */ +final class AuthSubmitUserInputParams implements BaseModel +{ + /** @use SdkModel<AuthSubmitUserInputParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $bridgeID; + + #[Required] + public string $loginProcessID; + + /** @var array<string,string> $body */ + #[Required(map: 'string')] + public array $body; + + /** + * `new AuthSubmitUserInputParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AuthSubmitUserInputParams::with(bridgeID: ..., loginProcessID: ..., body: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AuthSubmitUserInputParams) + * ->withBridgeID(...) + * ->withLoginProcessID(...) + * ->withBody(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param array<string,string> $body + */ + public static function with( + string $bridgeID, + string $loginProcessID, + array $body + ): self { + $self = new self; + + $self['bridgeID'] = $bridgeID; + $self['loginProcessID'] = $loginProcessID; + $self['body'] = $body; + + return $self; + } + + public function withBridgeID(string $bridgeID): self + { + $self = clone $this; + $self['bridgeID'] = $bridgeID; + + return $self; + } + + public function withLoginProcessID(string $loginProcessID): self + { + $self = clone $this; + $self['loginProcessID'] = $loginProcessID; + + return $self; + } + + /** + * @param array<string,string> $body + */ + public function withBody(array $body): self + { + $self = clone $this; + $self['body'] = $body; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse.php new file mode 100644 index 0000000..e1a159a --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Concerns\SdkUnion; +use BeeperDesktop\Core\Conversion\Contracts\Converter; +use BeeperDesktop\Core\Conversion\Contracts\ConverterSource; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember3; + +/** + * A step in a login process. + * + * @phpstan-import-type UnionMember0Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0 + * @phpstan-import-type UnionMember1Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1 + * @phpstan-import-type UnionMember2Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2 + * @phpstan-import-type UnionMember3Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember3 + * + * @phpstan-type AuthSubmitUserInputResponseVariants = UnionMember0|UnionMember1|UnionMember2|UnionMember3 + * @phpstan-type AuthSubmitUserInputResponseShape = AuthSubmitUserInputResponseVariants|UnionMember0Shape|UnionMember1Shape|UnionMember2Shape|UnionMember3Shape + */ +final class AuthSubmitUserInputResponse implements ConverterSource +{ + use SdkUnion; + + /** + * @return list<string|Converter|ConverterSource>|array<string,string|Converter|ConverterSource> + */ + public static function variants(): array + { + return [ + UnionMember0::class, + UnionMember1::class, + UnionMember2::class, + UnionMember3::class, + ]; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0.php new file mode 100644 index 0000000..754aac5 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0.php @@ -0,0 +1,159 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0\DisplayAndWait; + +/** + * Display and wait login step. + * + * @phpstan-import-type DisplayAndWaitShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0\DisplayAndWait + * + * @phpstan-type UnionMember0Shape = array{ + * displayAndWait: DisplayAndWait|DisplayAndWaitShape, + * type: 'display_and_wait', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember0 implements BaseModel +{ + /** @use SdkModel<UnionMember0Shape> */ + use SdkModel; + + /** @var 'display_and_wait' $type */ + #[Required] + public string $type = 'display_and_wait'; + + /** + * Parameters for the display and wait login step. + */ + #[Required('display_and_wait')] + public DisplayAndWait $displayAndWait; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember0()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember0::with(displayAndWait: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember0)->withDisplayAndWait(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param DisplayAndWait|DisplayAndWaitShape $displayAndWait + */ + public static function with( + DisplayAndWait|array $displayAndWait, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['displayAndWait'] = $displayAndWait; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Parameters for the display and wait login step. + * + * @param DisplayAndWait|DisplayAndWaitShape $displayAndWait + */ + public function withDisplayAndWait( + DisplayAndWait|array $displayAndWait + ): self { + $self = clone $this; + $self['displayAndWait'] = $displayAndWait; + + return $self; + } + + /** + * @param 'display_and_wait' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0/DisplayAndWait.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0/DisplayAndWait.php new file mode 100644 index 0000000..4805da0 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0/DisplayAndWait.php @@ -0,0 +1,120 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0\DisplayAndWait\Type; + +/** + * Parameters for the display and wait login step. + * + * @phpstan-type DisplayAndWaitShape = array{ + * type: Type|value-of<Type>, data?: string|null, imageURL?: string|null + * } + */ +final class DisplayAndWait implements BaseModel +{ + /** @use SdkModel<DisplayAndWaitShape> */ + use SdkModel; + + /** + * The type of thing to display. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * The thing to display (raw data for QR, unicode emoji for emoji, plain string for code). + */ + #[Optional] + public ?string $data; + + /** + * 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. + */ + #[Optional('image_url')] + public ?string $imageURL; + + /** + * `new DisplayAndWait()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * DisplayAndWait::with(type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new DisplayAndWait)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + */ + public static function with( + Type|string $type, + ?string $data = null, + ?string $imageURL = null + ): self { + $self = new self; + + $self['type'] = $type; + + null !== $data && $self['data'] = $data; + null !== $imageURL && $self['imageURL'] = $imageURL; + + return $self; + } + + /** + * The type of thing to display. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * The thing to display (raw data for QR, unicode emoji for emoji, plain string for code). + */ + public function withData(string $data): self + { + $self = clone $this; + $self['data'] = $data; + + return $self; + } + + /** + * 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. + */ + public function withImageURL(string $imageURL): self + { + $self = clone $this; + $self['imageURL'] = $imageURL; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0/DisplayAndWait/Type.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0/DisplayAndWait/Type.php new file mode 100644 index 0000000..30b449e --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember0/DisplayAndWait/Type.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0\DisplayAndWait; + +/** + * The type of thing to display. + */ +enum Type: string +{ + case QR = 'qr'; + + case EMOJI = 'emoji'; + + case CODE = 'code'; + + case NOTHING = 'nothing'; +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1.php new file mode 100644 index 0000000..b77e179 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput; + +/** + * User input login step. + * + * @phpstan-import-type UserInputShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput + * + * @phpstan-type UnionMember1Shape = array{ + * type: 'user_input', + * userInput: UserInput|UserInputShape, + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember1 implements BaseModel +{ + /** @use SdkModel<UnionMember1Shape> */ + use SdkModel; + + /** @var 'user_input' $type */ + #[Required] + public string $type = 'user_input'; + + /** + * Parameters for the user input login step. + */ + #[Required('user_input')] + public UserInput $userInput; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember1()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember1::with(userInput: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember1)->withUserInput(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param UserInput|UserInputShape $userInput + */ + public static function with( + UserInput|array $userInput, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['userInput'] = $userInput; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * @param 'user_input' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Parameters for the user input login step. + * + * @param UserInput|UserInputShape $userInput + */ + public function withUserInput(UserInput|array $userInput): self + { + $self = clone $this; + $self['userInput'] = $userInput; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput.php new file mode 100644 index 0000000..dca5fe2 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput.php @@ -0,0 +1,109 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Attachment; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Field; + +/** + * Parameters for the user input login step. + * + * @phpstan-import-type FieldShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Field + * @phpstan-import-type AttachmentShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Attachment + * + * @phpstan-type UserInputShape = array{ + * fields: list<Field|FieldShape>, + * attachments?: list<Attachment|AttachmentShape>|null, + * } + */ +final class UserInput implements BaseModel +{ + /** @use SdkModel<UserInputShape> */ + use SdkModel; + + /** + * The list of fields that the user is requested to fill. + * + * @var list<Field> $fields + */ + #[Required(list: Field::class)] + public array $fields; + + /** + * A list of media attachments to show the user alongside the form fields. + * + * @var list<Attachment>|null $attachments + */ + #[Optional(list: Attachment::class)] + public ?array $attachments; + + /** + * `new UserInput()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UserInput::with(fields: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UserInput)->withFields(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Field|FieldShape> $fields + * @param list<Attachment|AttachmentShape>|null $attachments + */ + public static function with(array $fields, ?array $attachments = null): self + { + $self = new self; + + $self['fields'] = $fields; + + null !== $attachments && $self['attachments'] = $attachments; + + return $self; + } + + /** + * The list of fields that the user is requested to fill. + * + * @param list<Field|FieldShape> $fields + */ + public function withFields(array $fields): self + { + $self = clone $this; + $self['fields'] = $fields; + + return $self; + } + + /** + * A list of media attachments to show the user alongside the form fields. + * + * @param list<Attachment|AttachmentShape> $attachments + */ + public function withAttachments(array $attachments): self + { + $self = clone $this; + $self['attachments'] = $attachments; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment.php new file mode 100644 index 0000000..22f61e3 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment.php @@ -0,0 +1,148 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Attachment\Info; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Attachment\Type; + +/** + * A media attachment to show the user. + * + * @phpstan-import-type InfoShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Attachment\Info + * + * @phpstan-type AttachmentShape = array{ + * content: string, + * filename: string, + * type: Type|value-of<Type>, + * info?: null|Info|InfoShape, + * } + */ +final class Attachment implements BaseModel +{ + /** @use SdkModel<AttachmentShape> */ + use SdkModel; + + /** + * The raw file content for the attachment encoded in base64. + */ + #[Required] + public string $content; + + /** + * The filename for the media attachment. + */ + #[Required] + public string $filename; + + /** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + */ + #[Optional] + public ?Info $info; + + /** + * `new Attachment()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Attachment::with(content: ..., filename: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Attachment)->withContent(...)->withFilename(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + * @param Info|InfoShape|null $info + */ + public static function with( + string $content, + string $filename, + Type|string $type, + Info|array|null $info = null, + ): self { + $self = new self; + + $self['content'] = $content; + $self['filename'] = $filename; + $self['type'] = $type; + + null !== $info && $self['info'] = $info; + + return $self; + } + + /** + * The raw file content for the attachment encoded in base64. + */ + public function withContent(string $content): self + { + $self = clone $this; + $self['content'] = $content; + + return $self; + } + + /** + * The filename for the media attachment. + */ + public function withFilename(string $filename): self + { + $self = clone $this; + $self['filename'] = $filename; + + return $self; + } + + /** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + * + * @param Info|InfoShape $info + */ + public function withInfo(Info|array $info): self + { + $self = clone $this; + $self['info'] = $info; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment/Info.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment/Info.php new file mode 100644 index 0000000..bcb6f83 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment/Info.php @@ -0,0 +1,116 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Attachment; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + * + * @phpstan-type InfoShape = array{ + * h?: float|null, mimetype?: string|null, size?: float|null, w?: float|null + * } + */ +final class Info implements BaseModel +{ + /** @use SdkModel<InfoShape> */ + use SdkModel; + + /** + * The height of the media in pixels. Only applicable for images and videos. + */ + #[Optional] + public ?float $h; + + /** + * The MIME type for the media content. + */ + #[Optional] + public ?string $mimetype; + + /** + * The size of the media content in number of bytes. Strongly recommended to include. + */ + #[Optional] + public ?float $size; + + /** + * The width of the media in pixels. Only applicable for images and videos. + */ + #[Optional] + public ?float $w; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?float $h = null, + ?string $mimetype = null, + ?float $size = null, + ?float $w = null, + ): self { + $self = new self; + + null !== $h && $self['h'] = $h; + null !== $mimetype && $self['mimetype'] = $mimetype; + null !== $size && $self['size'] = $size; + null !== $w && $self['w'] = $w; + + return $self; + } + + /** + * The height of the media in pixels. Only applicable for images and videos. + */ + public function withH(float $h): self + { + $self = clone $this; + $self['h'] = $h; + + return $self; + } + + /** + * The MIME type for the media content. + */ + public function withMimetype(string $mimetype): self + { + $self = clone $this; + $self['mimetype'] = $mimetype; + + return $self; + } + + /** + * The size of the media content in number of bytes. Strongly recommended to include. + */ + public function withSize(float $size): self + { + $self = clone $this; + $self['size'] = $size; + + return $self; + } + + /** + * The width of the media in pixels. Only applicable for images and videos. + */ + public function withW(float $w): self + { + $self = clone $this; + $self['w'] = $w; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment/Type.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment/Type.php new file mode 100644 index 0000000..e1462da --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Attachment/Type.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Attachment; + +/** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + */ +enum Type: string +{ + case M_IMAGE = 'm.image'; + + case M_AUDIO = 'm.audio'; +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Field.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Field.php new file mode 100644 index 0000000..107a4df --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Field.php @@ -0,0 +1,207 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Field\Type; + +/** + * A field that the user can fill. + * + * @phpstan-type FieldShape = array{ + * id: string, + * name: string, + * type: Type|value-of<Type>, + * defaultValue?: string|null, + * description?: string|null, + * options?: list<string>|null, + * pattern?: string|null, + * } + */ +final class Field implements BaseModel +{ + /** @use SdkModel<FieldShape> */ + use SdkModel; + + /** + * The internal ID of the field. This must be used as the key in the object when submitting the data back to the bridge. + */ + #[Required] + public string $id; + + /** + * The name of the field shown to the user. + */ + #[Required] + public string $name; + + /** + * The type of field. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * A default value that the client can pre-fill the field with. + */ + #[Optional('default_value')] + public ?string $defaultValue; + + /** + * A more detailed description of the field shown to the user. + */ + #[Optional] + public ?string $description; + + /** + * For fields of type select, the valid options. + * + * @var list<string>|null $options + */ + #[Optional(list: 'string')] + public ?array $options; + + /** + * A regular expression that the field value must match. + */ + #[Optional] + public ?string $pattern; + + /** + * `new Field()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Field::with(id: ..., name: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Field)->withID(...)->withName(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + * @param list<string>|null $options + */ + public static function with( + string $id, + string $name, + Type|string $type, + ?string $defaultValue = null, + ?string $description = null, + ?array $options = null, + ?string $pattern = null, + ): self { + $self = new self; + + $self['id'] = $id; + $self['name'] = $name; + $self['type'] = $type; + + null !== $defaultValue && $self['defaultValue'] = $defaultValue; + null !== $description && $self['description'] = $description; + null !== $options && $self['options'] = $options; + null !== $pattern && $self['pattern'] = $pattern; + + return $self; + } + + /** + * The internal ID of the field. This must be used as the key in the object when submitting the data back to the bridge. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * The name of the field shown to the user. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The type of field. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * A default value that the client can pre-fill the field with. + */ + public function withDefaultValue(string $defaultValue): self + { + $self = clone $this; + $self['defaultValue'] = $defaultValue; + + return $self; + } + + /** + * A more detailed description of the field shown to the user. + */ + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * For fields of type select, the valid options. + * + * @param list<string> $options + */ + public function withOptions(array $options): self + { + $self = clone $this; + $self['options'] = $options; + + return $self; + } + + /** + * A regular expression that the field value must match. + */ + public function withPattern(string $pattern): self + { + $self = clone $this; + $self['pattern'] = $pattern; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Field/Type.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Field/Type.php new file mode 100644 index 0000000..69a2d40 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember1/UserInput/Field/Type.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1\UserInput\Field; + +/** + * The type of field. + */ +enum Type: string +{ + case USERNAME = 'username'; + + case PHONE_NUMBER = 'phone_number'; + + case EMAIL = 'email'; + + case PASSWORD = 'password'; + + case _2FA_CODE = '2fa_code'; + + case TOKEN = 'token'; + + case URL = 'url'; + + case DOMAIN = 'domain'; + + case SELECT = 'select'; +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2.php new file mode 100644 index 0000000..d2417dc --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2\Cookies; + +/** + * Cookie login step. + * + * @phpstan-import-type CookiesShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2\Cookies + * + * @phpstan-type UnionMember2Shape = array{ + * cookies: Cookies|CookiesShape, + * type: 'cookies', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember2 implements BaseModel +{ + /** @use SdkModel<UnionMember2Shape> */ + use SdkModel; + + /** @var 'cookies' $type */ + #[Required] + public string $type = 'cookies'; + + /** + * Parameters for the cookie login step. + */ + #[Required] + public Cookies $cookies; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember2()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember2::with(cookies: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember2)->withCookies(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Cookies|CookiesShape $cookies + */ + public static function with( + Cookies|array $cookies, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['cookies'] = $cookies; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Parameters for the cookie login step. + * + * @param Cookies|CookiesShape $cookies + */ + public function withCookies(Cookies|array $cookies): self + { + $self = clone $this; + $self['cookies'] = $cookies; + + return $self; + } + + /** + * @param 'cookies' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies.php new file mode 100644 index 0000000..8440f87 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies.php @@ -0,0 +1,176 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2\Cookies\Field; + +/** + * Parameters for the cookie login step. + * + * @phpstan-import-type FieldShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2\Cookies\Field + * + * @phpstan-type CookiesShape = array{ + * fields: list<Field|FieldShape>, + * url: string, + * extractJs?: string|null, + * userAgent?: string|null, + * waitForURLPattern?: string|null, + * } + */ +final class Cookies implements BaseModel +{ + /** @use SdkModel<CookiesShape> */ + use SdkModel; + + /** + * The list of cookies or other stored data that must be extracted. + * + * @var list<Field> $fields + */ + #[Required(list: Field::class)] + public array $fields; + + /** + * The URL to open when using a webview to extract cookies. + */ + #[Required] + public string $url; + + /** + * 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. + */ + #[Optional('extract_js')] + public ?string $extractJs; + + /** + * An optional user agent that the webview should use. + */ + #[Optional('user_agent')] + public ?string $userAgent; + + /** + * 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. + */ + #[Optional('wait_for_url_pattern')] + public ?string $waitForURLPattern; + + /** + * `new Cookies()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Cookies::with(fields: ..., url: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Cookies)->withFields(...)->withURL(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Field|FieldShape> $fields + */ + public static function with( + array $fields, + string $url, + ?string $extractJs = null, + ?string $userAgent = null, + ?string $waitForURLPattern = null, + ): self { + $self = new self; + + $self['fields'] = $fields; + $self['url'] = $url; + + null !== $extractJs && $self['extractJs'] = $extractJs; + null !== $userAgent && $self['userAgent'] = $userAgent; + null !== $waitForURLPattern && $self['waitForURLPattern'] = $waitForURLPattern; + + return $self; + } + + /** + * The list of cookies or other stored data that must be extracted. + * + * @param list<Field|FieldShape> $fields + */ + public function withFields(array $fields): self + { + $self = clone $this; + $self['fields'] = $fields; + + return $self; + } + + /** + * The URL to open when using a webview to extract cookies. + */ + public function withURL(string $url): self + { + $self = clone $this; + $self['url'] = $url; + + return $self; + } + + /** + * 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. + */ + public function withExtractJs(string $extractJs): self + { + $self = clone $this; + $self['extractJs'] = $extractJs; + + return $self; + } + + /** + * An optional user agent that the webview should use. + */ + public function withUserAgent(string $userAgent): self + { + $self = clone $this; + $self['userAgent'] = $userAgent; + + return $self; + } + + /** + * 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. + */ + public function withWaitForURLPattern(string $waitForURLPattern): self + { + $self = clone $this; + $self['waitForURLPattern'] = $waitForURLPattern; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies/Field.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies/Field.php new file mode 100644 index 0000000..7bf33fd --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies/Field.php @@ -0,0 +1,142 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2\Cookies; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2\Cookies\Field\Type; + +/** + * An individual cookie or other stored data item that must be extracted. + * + * @phpstan-type FieldShape = array{ + * name: string, + * type: Type|value-of<Type>, + * cookieDomain?: string|null, + * requestURLRegex?: string|null, + * } + */ +final class Field implements BaseModel +{ + /** @use SdkModel<FieldShape> */ + use SdkModel; + + /** + * The name of the item to extract. + */ + #[Required] + public string $name; + + /** + * The type of data to extract. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * For the `cookie` type, the domain of the cookie. + */ + #[Optional('cookie_domain')] + public ?string $cookieDomain; + + /** + * For the `request_header` and `request_body` types, a regex that matches the URLs from which the values can be extracted. + */ + #[Optional('request_url_regex')] + public ?string $requestURLRegex; + + /** + * `new Field()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Field::with(name: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Field)->withName(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + */ + public static function with( + string $name, + Type|string $type, + ?string $cookieDomain = null, + ?string $requestURLRegex = null, + ): self { + $self = new self; + + $self['name'] = $name; + $self['type'] = $type; + + null !== $cookieDomain && $self['cookieDomain'] = $cookieDomain; + null !== $requestURLRegex && $self['requestURLRegex'] = $requestURLRegex; + + return $self; + } + + /** + * The name of the item to extract. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The type of data to extract. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * For the `cookie` type, the domain of the cookie. + */ + public function withCookieDomain(string $cookieDomain): self + { + $self = clone $this; + $self['cookieDomain'] = $cookieDomain; + + return $self; + } + + /** + * For the `request_header` and `request_body` types, a regex that matches the URLs from which the values can be extracted. + */ + public function withRequestURLRegex(string $requestURLRegex): self + { + $self = clone $this; + $self['requestURLRegex'] = $requestURLRegex; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies/Field/Type.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies/Field/Type.php new file mode 100644 index 0000000..9592dd3 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember2/Cookies/Field/Type.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2\Cookies\Field; + +/** + * The type of data to extract. + */ +enum Type: string +{ + case COOKIE = 'cookie'; + + case LOCAL_STORAGE = 'local_storage'; + + case REQUEST_HEADER = 'request_header'; + + case REQUEST_BODY = 'request_body'; + + case SPECIAL = 'special'; +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember3.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember3.php new file mode 100644 index 0000000..aa6e43d --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember3.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember3\Complete; + +/** + * Login complete. + * + * @phpstan-import-type CompleteShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember3\Complete + * + * @phpstan-type UnionMember3Shape = array{ + * complete: Complete|CompleteShape, + * type: 'complete', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember3 implements BaseModel +{ + /** @use SdkModel<UnionMember3Shape> */ + use SdkModel; + + /** @var 'complete' $type */ + #[Required] + public string $type = 'complete'; + + /** + * Information about the completed login. + */ + #[Required] + public Complete $complete; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember3()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember3::with(complete: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember3)->withComplete(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Complete|CompleteShape $complete + */ + public static function with( + Complete|array $complete, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['complete'] = $complete; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Information about the completed login. + * + * @param Complete|CompleteShape $complete + */ + public function withComplete(Complete|array $complete): self + { + $self = clone $this; + $self['complete'] = $complete; + + return $self; + } + + /** + * @param 'complete' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember3/Complete.php b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember3/Complete.php new file mode 100644 index 0000000..b6eedeb --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthSubmitUserInputResponse/UnionMember3/Complete.php @@ -0,0 +1,56 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember3; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Information about the completed login. + * + * @phpstan-type CompleteShape = array{userLoginID?: string|null} + */ +final class Complete implements BaseModel +{ + /** @use SdkModel<CompleteShape> */ + use SdkModel; + + /** + * The unique ID of a login. Defined by the network connector. + */ + #[Optional('user_login_id')] + public ?string $userLoginID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $userLoginID = null): self + { + $self = new self; + + null !== $userLoginID && $self['userLoginID'] = $userLoginID; + + return $self; + } + + /** + * The unique ID of a login. Defined by the network connector. + */ + public function withUserLoginID(string $userLoginID): self + { + $self = clone $this; + $self['userLoginID'] = $userLoginID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepParams.php b/src/Matrix/Bridges/Auth/AuthWaitForStepParams.php new file mode 100644 index 0000000..2989707 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepParams.php @@ -0,0 +1,82 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Wait for the next step after displaying data to the user. + * + * @see BeeperDesktop\Services\Matrix\Bridges\AuthService::waitForStep() + * + * @phpstan-type AuthWaitForStepParamsShape = array{ + * bridgeID: string, loginProcessID: string + * } + */ +final class AuthWaitForStepParams implements BaseModel +{ + /** @use SdkModel<AuthWaitForStepParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $bridgeID; + + #[Required] + public string $loginProcessID; + + /** + * `new AuthWaitForStepParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AuthWaitForStepParams::with(bridgeID: ..., loginProcessID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AuthWaitForStepParams)->withBridgeID(...)->withLoginProcessID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $bridgeID, string $loginProcessID): self + { + $self = new self; + + $self['bridgeID'] = $bridgeID; + $self['loginProcessID'] = $loginProcessID; + + return $self; + } + + public function withBridgeID(string $bridgeID): self + { + $self = clone $this; + $self['bridgeID'] = $bridgeID; + + return $self; + } + + public function withLoginProcessID(string $loginProcessID): self + { + $self = clone $this; + $self['loginProcessID'] = $loginProcessID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse.php new file mode 100644 index 0000000..1d5cc94 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Concerns\SdkUnion; +use BeeperDesktop\Core\Conversion\Contracts\Converter; +use BeeperDesktop\Core\Conversion\Contracts\ConverterSource; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember3; + +/** + * A step in a login process. + * + * @phpstan-import-type UnionMember0Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0 + * @phpstan-import-type UnionMember1Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1 + * @phpstan-import-type UnionMember2Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2 + * @phpstan-import-type UnionMember3Shape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember3 + * + * @phpstan-type AuthWaitForStepResponseVariants = UnionMember0|UnionMember1|UnionMember2|UnionMember3 + * @phpstan-type AuthWaitForStepResponseShape = AuthWaitForStepResponseVariants|UnionMember0Shape|UnionMember1Shape|UnionMember2Shape|UnionMember3Shape + */ +final class AuthWaitForStepResponse implements ConverterSource +{ + use SdkUnion; + + /** + * @return list<string|Converter|ConverterSource>|array<string,string|Converter|ConverterSource> + */ + public static function variants(): array + { + return [ + UnionMember0::class, + UnionMember1::class, + UnionMember2::class, + UnionMember3::class, + ]; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0.php new file mode 100644 index 0000000..f615123 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0.php @@ -0,0 +1,159 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0\DisplayAndWait; + +/** + * Display and wait login step. + * + * @phpstan-import-type DisplayAndWaitShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0\DisplayAndWait + * + * @phpstan-type UnionMember0Shape = array{ + * displayAndWait: DisplayAndWait|DisplayAndWaitShape, + * type: 'display_and_wait', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember0 implements BaseModel +{ + /** @use SdkModel<UnionMember0Shape> */ + use SdkModel; + + /** @var 'display_and_wait' $type */ + #[Required] + public string $type = 'display_and_wait'; + + /** + * Parameters for the display and wait login step. + */ + #[Required('display_and_wait')] + public DisplayAndWait $displayAndWait; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember0()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember0::with(displayAndWait: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember0)->withDisplayAndWait(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param DisplayAndWait|DisplayAndWaitShape $displayAndWait + */ + public static function with( + DisplayAndWait|array $displayAndWait, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['displayAndWait'] = $displayAndWait; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Parameters for the display and wait login step. + * + * @param DisplayAndWait|DisplayAndWaitShape $displayAndWait + */ + public function withDisplayAndWait( + DisplayAndWait|array $displayAndWait + ): self { + $self = clone $this; + $self['displayAndWait'] = $displayAndWait; + + return $self; + } + + /** + * @param 'display_and_wait' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0/DisplayAndWait.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0/DisplayAndWait.php new file mode 100644 index 0000000..99d7a9f --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0/DisplayAndWait.php @@ -0,0 +1,120 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0\DisplayAndWait\Type; + +/** + * Parameters for the display and wait login step. + * + * @phpstan-type DisplayAndWaitShape = array{ + * type: Type|value-of<Type>, data?: string|null, imageURL?: string|null + * } + */ +final class DisplayAndWait implements BaseModel +{ + /** @use SdkModel<DisplayAndWaitShape> */ + use SdkModel; + + /** + * The type of thing to display. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * The thing to display (raw data for QR, unicode emoji for emoji, plain string for code). + */ + #[Optional] + public ?string $data; + + /** + * 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. + */ + #[Optional('image_url')] + public ?string $imageURL; + + /** + * `new DisplayAndWait()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * DisplayAndWait::with(type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new DisplayAndWait)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + */ + public static function with( + Type|string $type, + ?string $data = null, + ?string $imageURL = null + ): self { + $self = new self; + + $self['type'] = $type; + + null !== $data && $self['data'] = $data; + null !== $imageURL && $self['imageURL'] = $imageURL; + + return $self; + } + + /** + * The type of thing to display. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * The thing to display (raw data for QR, unicode emoji for emoji, plain string for code). + */ + public function withData(string $data): self + { + $self = clone $this; + $self['data'] = $data; + + return $self; + } + + /** + * 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. + */ + public function withImageURL(string $imageURL): self + { + $self = clone $this; + $self['imageURL'] = $imageURL; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0/DisplayAndWait/Type.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0/DisplayAndWait/Type.php new file mode 100644 index 0000000..61d7fc3 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember0/DisplayAndWait/Type.php @@ -0,0 +1,19 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0\DisplayAndWait; + +/** + * The type of thing to display. + */ +enum Type: string +{ + case QR = 'qr'; + + case EMOJI = 'emoji'; + + case CODE = 'code'; + + case NOTHING = 'nothing'; +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1.php new file mode 100644 index 0000000..79df813 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput; + +/** + * User input login step. + * + * @phpstan-import-type UserInputShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput + * + * @phpstan-type UnionMember1Shape = array{ + * type: 'user_input', + * userInput: UserInput|UserInputShape, + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember1 implements BaseModel +{ + /** @use SdkModel<UnionMember1Shape> */ + use SdkModel; + + /** @var 'user_input' $type */ + #[Required] + public string $type = 'user_input'; + + /** + * Parameters for the user input login step. + */ + #[Required('user_input')] + public UserInput $userInput; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember1()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember1::with(userInput: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember1)->withUserInput(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param UserInput|UserInputShape $userInput + */ + public static function with( + UserInput|array $userInput, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['userInput'] = $userInput; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * @param 'user_input' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Parameters for the user input login step. + * + * @param UserInput|UserInputShape $userInput + */ + public function withUserInput(UserInput|array $userInput): self + { + $self = clone $this; + $self['userInput'] = $userInput; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput.php new file mode 100644 index 0000000..fe16f6f --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput.php @@ -0,0 +1,109 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Attachment; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Field; + +/** + * Parameters for the user input login step. + * + * @phpstan-import-type FieldShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Field + * @phpstan-import-type AttachmentShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Attachment + * + * @phpstan-type UserInputShape = array{ + * fields: list<Field|FieldShape>, + * attachments?: list<Attachment|AttachmentShape>|null, + * } + */ +final class UserInput implements BaseModel +{ + /** @use SdkModel<UserInputShape> */ + use SdkModel; + + /** + * The list of fields that the user is requested to fill. + * + * @var list<Field> $fields + */ + #[Required(list: Field::class)] + public array $fields; + + /** + * A list of media attachments to show the user alongside the form fields. + * + * @var list<Attachment>|null $attachments + */ + #[Optional(list: Attachment::class)] + public ?array $attachments; + + /** + * `new UserInput()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UserInput::with(fields: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UserInput)->withFields(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Field|FieldShape> $fields + * @param list<Attachment|AttachmentShape>|null $attachments + */ + public static function with(array $fields, ?array $attachments = null): self + { + $self = new self; + + $self['fields'] = $fields; + + null !== $attachments && $self['attachments'] = $attachments; + + return $self; + } + + /** + * The list of fields that the user is requested to fill. + * + * @param list<Field|FieldShape> $fields + */ + public function withFields(array $fields): self + { + $self = clone $this; + $self['fields'] = $fields; + + return $self; + } + + /** + * A list of media attachments to show the user alongside the form fields. + * + * @param list<Attachment|AttachmentShape> $attachments + */ + public function withAttachments(array $attachments): self + { + $self = clone $this; + $self['attachments'] = $attachments; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment.php new file mode 100644 index 0000000..23679de --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment.php @@ -0,0 +1,148 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Attachment\Info; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Attachment\Type; + +/** + * A media attachment to show the user. + * + * @phpstan-import-type InfoShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Attachment\Info + * + * @phpstan-type AttachmentShape = array{ + * content: string, + * filename: string, + * type: Type|value-of<Type>, + * info?: null|Info|InfoShape, + * } + */ +final class Attachment implements BaseModel +{ + /** @use SdkModel<AttachmentShape> */ + use SdkModel; + + /** + * The raw file content for the attachment encoded in base64. + */ + #[Required] + public string $content; + + /** + * The filename for the media attachment. + */ + #[Required] + public string $filename; + + /** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + */ + #[Optional] + public ?Info $info; + + /** + * `new Attachment()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Attachment::with(content: ..., filename: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Attachment)->withContent(...)->withFilename(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + * @param Info|InfoShape|null $info + */ + public static function with( + string $content, + string $filename, + Type|string $type, + Info|array|null $info = null, + ): self { + $self = new self; + + $self['content'] = $content; + $self['filename'] = $filename; + $self['type'] = $type; + + null !== $info && $self['info'] = $info; + + return $self; + } + + /** + * The raw file content for the attachment encoded in base64. + */ + public function withContent(string $content): self + { + $self = clone $this; + $self['content'] = $content; + + return $self; + } + + /** + * The filename for the media attachment. + */ + public function withFilename(string $filename): self + { + $self = clone $this; + $self['filename'] = $filename; + + return $self; + } + + /** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + * + * @param Info|InfoShape $info + */ + public function withInfo(Info|array $info): self + { + $self = clone $this; + $self['info'] = $info; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment/Info.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment/Info.php new file mode 100644 index 0000000..9d3db8e --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment/Info.php @@ -0,0 +1,116 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Attachment; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Optional but recommended metadata for the attachment. Can generally be derived from the raw content if omitted. + * + * @phpstan-type InfoShape = array{ + * h?: float|null, mimetype?: string|null, size?: float|null, w?: float|null + * } + */ +final class Info implements BaseModel +{ + /** @use SdkModel<InfoShape> */ + use SdkModel; + + /** + * The height of the media in pixels. Only applicable for images and videos. + */ + #[Optional] + public ?float $h; + + /** + * The MIME type for the media content. + */ + #[Optional] + public ?string $mimetype; + + /** + * The size of the media content in number of bytes. Strongly recommended to include. + */ + #[Optional] + public ?float $size; + + /** + * The width of the media in pixels. Only applicable for images and videos. + */ + #[Optional] + public ?float $w; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?float $h = null, + ?string $mimetype = null, + ?float $size = null, + ?float $w = null, + ): self { + $self = new self; + + null !== $h && $self['h'] = $h; + null !== $mimetype && $self['mimetype'] = $mimetype; + null !== $size && $self['size'] = $size; + null !== $w && $self['w'] = $w; + + return $self; + } + + /** + * The height of the media in pixels. Only applicable for images and videos. + */ + public function withH(float $h): self + { + $self = clone $this; + $self['h'] = $h; + + return $self; + } + + /** + * The MIME type for the media content. + */ + public function withMimetype(string $mimetype): self + { + $self = clone $this; + $self['mimetype'] = $mimetype; + + return $self; + } + + /** + * The size of the media content in number of bytes. Strongly recommended to include. + */ + public function withSize(float $size): self + { + $self = clone $this; + $self['size'] = $size; + + return $self; + } + + /** + * The width of the media in pixels. Only applicable for images and videos. + */ + public function withW(float $w): self + { + $self = clone $this; + $self['w'] = $w; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment/Type.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment/Type.php new file mode 100644 index 0000000..66f7ee8 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Attachment/Type.php @@ -0,0 +1,15 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Attachment; + +/** + * The type of media attachment, using the same media type identifiers as Matrix attachments. Only some are supported. + */ +enum Type: string +{ + case M_IMAGE = 'm.image'; + + case M_AUDIO = 'm.audio'; +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Field.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Field.php new file mode 100644 index 0000000..16a4260 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Field.php @@ -0,0 +1,207 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Field\Type; + +/** + * A field that the user can fill. + * + * @phpstan-type FieldShape = array{ + * id: string, + * name: string, + * type: Type|value-of<Type>, + * defaultValue?: string|null, + * description?: string|null, + * options?: list<string>|null, + * pattern?: string|null, + * } + */ +final class Field implements BaseModel +{ + /** @use SdkModel<FieldShape> */ + use SdkModel; + + /** + * The internal ID of the field. This must be used as the key in the object when submitting the data back to the bridge. + */ + #[Required] + public string $id; + + /** + * The name of the field shown to the user. + */ + #[Required] + public string $name; + + /** + * The type of field. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * A default value that the client can pre-fill the field with. + */ + #[Optional('default_value')] + public ?string $defaultValue; + + /** + * A more detailed description of the field shown to the user. + */ + #[Optional] + public ?string $description; + + /** + * For fields of type select, the valid options. + * + * @var list<string>|null $options + */ + #[Optional(list: 'string')] + public ?array $options; + + /** + * A regular expression that the field value must match. + */ + #[Optional] + public ?string $pattern; + + /** + * `new Field()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Field::with(id: ..., name: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Field)->withID(...)->withName(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + * @param list<string>|null $options + */ + public static function with( + string $id, + string $name, + Type|string $type, + ?string $defaultValue = null, + ?string $description = null, + ?array $options = null, + ?string $pattern = null, + ): self { + $self = new self; + + $self['id'] = $id; + $self['name'] = $name; + $self['type'] = $type; + + null !== $defaultValue && $self['defaultValue'] = $defaultValue; + null !== $description && $self['description'] = $description; + null !== $options && $self['options'] = $options; + null !== $pattern && $self['pattern'] = $pattern; + + return $self; + } + + /** + * The internal ID of the field. This must be used as the key in the object when submitting the data back to the bridge. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * The name of the field shown to the user. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The type of field. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * A default value that the client can pre-fill the field with. + */ + public function withDefaultValue(string $defaultValue): self + { + $self = clone $this; + $self['defaultValue'] = $defaultValue; + + return $self; + } + + /** + * A more detailed description of the field shown to the user. + */ + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * For fields of type select, the valid options. + * + * @param list<string> $options + */ + public function withOptions(array $options): self + { + $self = clone $this; + $self['options'] = $options; + + return $self; + } + + /** + * A regular expression that the field value must match. + */ + public function withPattern(string $pattern): self + { + $self = clone $this; + $self['pattern'] = $pattern; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Field/Type.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Field/Type.php new file mode 100644 index 0000000..26fb837 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember1/UserInput/Field/Type.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1\UserInput\Field; + +/** + * The type of field. + */ +enum Type: string +{ + case USERNAME = 'username'; + + case PHONE_NUMBER = 'phone_number'; + + case EMAIL = 'email'; + + case PASSWORD = 'password'; + + case _2FA_CODE = '2fa_code'; + + case TOKEN = 'token'; + + case URL = 'url'; + + case DOMAIN = 'domain'; + + case SELECT = 'select'; +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2.php new file mode 100644 index 0000000..5c6f6bf --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2\Cookies; + +/** + * Cookie login step. + * + * @phpstan-import-type CookiesShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2\Cookies + * + * @phpstan-type UnionMember2Shape = array{ + * cookies: Cookies|CookiesShape, + * type: 'cookies', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember2 implements BaseModel +{ + /** @use SdkModel<UnionMember2Shape> */ + use SdkModel; + + /** @var 'cookies' $type */ + #[Required] + public string $type = 'cookies'; + + /** + * Parameters for the cookie login step. + */ + #[Required] + public Cookies $cookies; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember2()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember2::with(cookies: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember2)->withCookies(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Cookies|CookiesShape $cookies + */ + public static function with( + Cookies|array $cookies, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['cookies'] = $cookies; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Parameters for the cookie login step. + * + * @param Cookies|CookiesShape $cookies + */ + public function withCookies(Cookies|array $cookies): self + { + $self = clone $this; + $self['cookies'] = $cookies; + + return $self; + } + + /** + * @param 'cookies' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies.php new file mode 100644 index 0000000..f839b94 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies.php @@ -0,0 +1,176 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2\Cookies\Field; + +/** + * Parameters for the cookie login step. + * + * @phpstan-import-type FieldShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2\Cookies\Field + * + * @phpstan-type CookiesShape = array{ + * fields: list<Field|FieldShape>, + * url: string, + * extractJs?: string|null, + * userAgent?: string|null, + * waitForURLPattern?: string|null, + * } + */ +final class Cookies implements BaseModel +{ + /** @use SdkModel<CookiesShape> */ + use SdkModel; + + /** + * The list of cookies or other stored data that must be extracted. + * + * @var list<Field> $fields + */ + #[Required(list: Field::class)] + public array $fields; + + /** + * The URL to open when using a webview to extract cookies. + */ + #[Required] + public string $url; + + /** + * 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. + */ + #[Optional('extract_js')] + public ?string $extractJs; + + /** + * An optional user agent that the webview should use. + */ + #[Optional('user_agent')] + public ?string $userAgent; + + /** + * 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. + */ + #[Optional('wait_for_url_pattern')] + public ?string $waitForURLPattern; + + /** + * `new Cookies()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Cookies::with(fields: ..., url: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Cookies)->withFields(...)->withURL(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Field|FieldShape> $fields + */ + public static function with( + array $fields, + string $url, + ?string $extractJs = null, + ?string $userAgent = null, + ?string $waitForURLPattern = null, + ): self { + $self = new self; + + $self['fields'] = $fields; + $self['url'] = $url; + + null !== $extractJs && $self['extractJs'] = $extractJs; + null !== $userAgent && $self['userAgent'] = $userAgent; + null !== $waitForURLPattern && $self['waitForURLPattern'] = $waitForURLPattern; + + return $self; + } + + /** + * The list of cookies or other stored data that must be extracted. + * + * @param list<Field|FieldShape> $fields + */ + public function withFields(array $fields): self + { + $self = clone $this; + $self['fields'] = $fields; + + return $self; + } + + /** + * The URL to open when using a webview to extract cookies. + */ + public function withURL(string $url): self + { + $self = clone $this; + $self['url'] = $url; + + return $self; + } + + /** + * 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. + */ + public function withExtractJs(string $extractJs): self + { + $self = clone $this; + $self['extractJs'] = $extractJs; + + return $self; + } + + /** + * An optional user agent that the webview should use. + */ + public function withUserAgent(string $userAgent): self + { + $self = clone $this; + $self['userAgent'] = $userAgent; + + return $self; + } + + /** + * 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. + */ + public function withWaitForURLPattern(string $waitForURLPattern): self + { + $self = clone $this; + $self['waitForURLPattern'] = $waitForURLPattern; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies/Field.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies/Field.php new file mode 100644 index 0000000..30a211e --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies/Field.php @@ -0,0 +1,142 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2\Cookies; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2\Cookies\Field\Type; + +/** + * An individual cookie or other stored data item that must be extracted. + * + * @phpstan-type FieldShape = array{ + * name: string, + * type: Type|value-of<Type>, + * cookieDomain?: string|null, + * requestURLRegex?: string|null, + * } + */ +final class Field implements BaseModel +{ + /** @use SdkModel<FieldShape> */ + use SdkModel; + + /** + * The name of the item to extract. + */ + #[Required] + public string $name; + + /** + * The type of data to extract. + * + * @var value-of<Type> $type + */ + #[Required(enum: Type::class)] + public string $type; + + /** + * For the `cookie` type, the domain of the cookie. + */ + #[Optional('cookie_domain')] + public ?string $cookieDomain; + + /** + * For the `request_header` and `request_body` types, a regex that matches the URLs from which the values can be extracted. + */ + #[Optional('request_url_regex')] + public ?string $requestURLRegex; + + /** + * `new Field()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Field::with(name: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Field)->withName(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Type|value-of<Type> $type + */ + public static function with( + string $name, + Type|string $type, + ?string $cookieDomain = null, + ?string $requestURLRegex = null, + ): self { + $self = new self; + + $self['name'] = $name; + $self['type'] = $type; + + null !== $cookieDomain && $self['cookieDomain'] = $cookieDomain; + null !== $requestURLRegex && $self['requestURLRegex'] = $requestURLRegex; + + return $self; + } + + /** + * The name of the item to extract. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The type of data to extract. + * + * @param Type|value-of<Type> $type + */ + public function withType(Type|string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * For the `cookie` type, the domain of the cookie. + */ + public function withCookieDomain(string $cookieDomain): self + { + $self = clone $this; + $self['cookieDomain'] = $cookieDomain; + + return $self; + } + + /** + * For the `request_header` and `request_body` types, a regex that matches the URLs from which the values can be extracted. + */ + public function withRequestURLRegex(string $requestURLRegex): self + { + $self = clone $this; + $self['requestURLRegex'] = $requestURLRegex; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies/Field/Type.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies/Field/Type.php new file mode 100644 index 0000000..cacbc5c --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember2/Cookies/Field/Type.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2\Cookies\Field; + +/** + * The type of data to extract. + */ +enum Type: string +{ + case COOKIE = 'cookie'; + + case LOCAL_STORAGE = 'local_storage'; + + case REQUEST_HEADER = 'request_header'; + + case REQUEST_BODY = 'request_body'; + + case SPECIAL = 'special'; +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember3.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember3.php new file mode 100644 index 0000000..d82276c --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember3.php @@ -0,0 +1,158 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember3\Complete; + +/** + * Login complete. + * + * @phpstan-import-type CompleteShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember3\Complete + * + * @phpstan-type UnionMember3Shape = array{ + * complete: Complete|CompleteShape, + * type: 'complete', + * instructions?: string|null, + * loginID?: string|null, + * stepID?: string|null, + * } + */ +final class UnionMember3 implements BaseModel +{ + /** @use SdkModel<UnionMember3Shape> */ + use SdkModel; + + /** @var 'complete' $type */ + #[Required] + public string $type = 'complete'; + + /** + * Information about the completed login. + */ + #[Required] + public Complete $complete; + + /** + * Human-readable instructions for completing this login step. + */ + #[Optional] + public ?string $instructions; + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + #[Optional('login_id')] + public ?string $loginID; + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + #[Optional('step_id')] + public ?string $stepID; + + /** + * `new UnionMember3()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UnionMember3::with(complete: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UnionMember3)->withComplete(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Complete|CompleteShape $complete + */ + public static function with( + Complete|array $complete, + ?string $instructions = null, + ?string $loginID = null, + ?string $stepID = null, + ): self { + $self = new self; + + $self['complete'] = $complete; + + null !== $instructions && $self['instructions'] = $instructions; + null !== $loginID && $self['loginID'] = $loginID; + null !== $stepID && $self['stepID'] = $stepID; + + return $self; + } + + /** + * Information about the completed login. + * + * @param Complete|CompleteShape $complete + */ + public function withComplete(Complete|array $complete): self + { + $self = clone $this; + $self['complete'] = $complete; + + return $self; + } + + /** + * @param 'complete' $type + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * Human-readable instructions for completing this login step. + */ + public function withInstructions(string $instructions): self + { + $self = clone $this; + $self['instructions'] = $instructions; + + return $self; + } + + /** + * An identifier for the current login process. Must be passed to execute more steps of the login. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * An unique ID identifying this step. This can be used to implement special behavior in clients. + */ + public function withStepID(string $stepID): self + { + $self = clone $this; + $self['stepID'] = $stepID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember3/Complete.php b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember3/Complete.php new file mode 100644 index 0000000..b984e41 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWaitForStepResponse/UnionMember3/Complete.php @@ -0,0 +1,56 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember3; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Information about the completed login. + * + * @phpstan-type CompleteShape = array{userLoginID?: string|null} + */ +final class Complete implements BaseModel +{ + /** @use SdkModel<CompleteShape> */ + use SdkModel; + + /** + * The unique ID of a login. Defined by the network connector. + */ + #[Optional('user_login_id')] + public ?string $userLoginID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $userLoginID = null): self + { + $self = new self; + + null !== $userLoginID && $self['userLoginID'] = $userLoginID; + + return $self; + } + + /** + * The unique ID of a login. Defined by the network connector. + */ + public function withUserLoginID(string $userLoginID): self + { + $self = clone $this; + $self['userLoginID'] = $userLoginID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWhoamiResponse.php b/src/Matrix/Bridges/Auth/AuthWhoamiResponse.php new file mode 100644 index 0000000..49974be --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWhoamiResponse.php @@ -0,0 +1,229 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\LoginFlow; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Network; + +/** + * Info about the bridge and user. + * + * @phpstan-import-type LoginFlowShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\LoginFlow + * @phpstan-import-type LoginShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login + * @phpstan-import-type NetworkShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Network + * + * @phpstan-type AuthWhoamiResponseShape = array{ + * bridgeBot: string, + * commandPrefix: string, + * homeserver: string, + * loginFlows: list<LoginFlow|LoginFlowShape>, + * logins: list<Login|LoginShape>, + * network: Network|NetworkShape, + * managementRoom?: string|null, + * } + */ +final class AuthWhoamiResponse implements BaseModel +{ + /** @use SdkModel<AuthWhoamiResponseShape> */ + use SdkModel; + + /** + * The Matrix user ID of the bridge bot. + */ + #[Required('bridge_bot')] + public string $bridgeBot; + + /** + * The command prefix used by this bridge. + */ + #[Required('command_prefix')] + public string $commandPrefix; + + /** + * The server name the bridge is running on. + */ + #[Required] + public string $homeserver; + + /** + * The login flows that the bridge supports. + * + * @var list<LoginFlow> $loginFlows + */ + #[Required('login_flows', list: LoginFlow::class)] + public array $loginFlows; + + /** + * The logins of the user who made the /whoami call. + * + * @var list<Login> $logins + */ + #[Required(list: Login::class)] + public array $logins; + + /** + * Info about the network that the bridge is bridging to. + */ + #[Required] + public Network $network; + + /** + * The Matrix management room ID of the user who made the /whoami call. + */ + #[Optional('management_room')] + public ?string $managementRoom; + + /** + * `new AuthWhoamiResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AuthWhoamiResponse::with( + * bridgeBot: ..., + * commandPrefix: ..., + * homeserver: ..., + * loginFlows: ..., + * logins: ..., + * network: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AuthWhoamiResponse) + * ->withBridgeBot(...) + * ->withCommandPrefix(...) + * ->withHomeserver(...) + * ->withLoginFlows(...) + * ->withLogins(...) + * ->withNetwork(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<LoginFlow|LoginFlowShape> $loginFlows + * @param list<Login|LoginShape> $logins + * @param Network|NetworkShape $network + */ + public static function with( + string $bridgeBot, + string $commandPrefix, + string $homeserver, + array $loginFlows, + array $logins, + Network|array $network, + ?string $managementRoom = null, + ): self { + $self = new self; + + $self['bridgeBot'] = $bridgeBot; + $self['commandPrefix'] = $commandPrefix; + $self['homeserver'] = $homeserver; + $self['loginFlows'] = $loginFlows; + $self['logins'] = $logins; + $self['network'] = $network; + + null !== $managementRoom && $self['managementRoom'] = $managementRoom; + + return $self; + } + + /** + * The Matrix user ID of the bridge bot. + */ + public function withBridgeBot(string $bridgeBot): self + { + $self = clone $this; + $self['bridgeBot'] = $bridgeBot; + + return $self; + } + + /** + * The command prefix used by this bridge. + */ + public function withCommandPrefix(string $commandPrefix): self + { + $self = clone $this; + $self['commandPrefix'] = $commandPrefix; + + return $self; + } + + /** + * The server name the bridge is running on. + */ + public function withHomeserver(string $homeserver): self + { + $self = clone $this; + $self['homeserver'] = $homeserver; + + return $self; + } + + /** + * The login flows that the bridge supports. + * + * @param list<LoginFlow|LoginFlowShape> $loginFlows + */ + public function withLoginFlows(array $loginFlows): self + { + $self = clone $this; + $self['loginFlows'] = $loginFlows; + + return $self; + } + + /** + * The logins of the user who made the /whoami call. + * + * @param list<Login|LoginShape> $logins + */ + public function withLogins(array $logins): self + { + $self = clone $this; + $self['logins'] = $logins; + + return $self; + } + + /** + * Info about the network that the bridge is bridging to. + * + * @param Network|NetworkShape $network + */ + public function withNetwork(Network|array $network): self + { + $self = clone $this; + $self['network'] = $network; + + return $self; + } + + /** + * The Matrix management room ID of the user who made the /whoami call. + */ + public function withManagementRoom(string $managementRoom): self + { + $self = clone $this; + $self['managementRoom'] = $managementRoom; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login.php b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login.php new file mode 100644 index 0000000..26c27b1 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login.php @@ -0,0 +1,167 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login\Profile; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login\State; + +/** + * The info of an individual login. + * + * @phpstan-import-type ProfileShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login\Profile + * @phpstan-import-type StateShape from \BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login\State + * + * @phpstan-type LoginShape = array{ + * id: string, + * name: string, + * profile: Profile|ProfileShape, + * state: State|StateShape, + * spaceRoom?: string|null, + * } + */ +final class Login implements BaseModel +{ + /** @use SdkModel<LoginShape> */ + use SdkModel; + + /** + * The unique ID of a login. Defined by the network connector. + */ + #[Required] + public string $id; + + /** + * A human-readable name for the login. Defined by the network connector. + */ + #[Required] + public string $name; + + /** + * The profile info of the logged-in user on the remote network. + */ + #[Required] + public Profile $profile; + + /** + * The connection status of an individual login. + */ + #[Required] + public State $state; + + /** + * The personal filtering space room ID for this login. + */ + #[Optional('space_room')] + public ?string $spaceRoom; + + /** + * `new Login()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Login::with(id: ..., name: ..., profile: ..., state: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Login)->withID(...)->withName(...)->withProfile(...)->withState(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Profile|ProfileShape $profile + * @param State|StateShape $state + */ + public static function with( + string $id, + string $name, + Profile|array $profile, + State|array $state, + ?string $spaceRoom = null, + ): self { + $self = new self; + + $self['id'] = $id; + $self['name'] = $name; + $self['profile'] = $profile; + $self['state'] = $state; + + null !== $spaceRoom && $self['spaceRoom'] = $spaceRoom; + + return $self; + } + + /** + * The unique ID of a login. Defined by the network connector. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * A human-readable name for the login. Defined by the network connector. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The profile info of the logged-in user on the remote network. + * + * @param Profile|ProfileShape $profile + */ + public function withProfile(Profile|array $profile): self + { + $self = clone $this; + $self['profile'] = $profile; + + return $self; + } + + /** + * The connection status of an individual login. + * + * @param State|StateShape $state + */ + public function withState(State|array $state): self + { + $self = clone $this; + $self['state'] = $state; + + return $self; + } + + /** + * The personal filtering space room ID for this login. + */ + public function withSpaceRoom(string $spaceRoom): self + { + $self = clone $this; + $self['spaceRoom'] = $spaceRoom; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/Profile.php b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/Profile.php new file mode 100644 index 0000000..a028b99 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/Profile.php @@ -0,0 +1,139 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * The profile info of the logged-in user on the remote network. + * + * @phpstan-type ProfileShape = array{ + * avatar?: string|null, + * email?: string|null, + * name?: string|null, + * phone?: string|null, + * username?: string|null, + * } + */ +final class Profile implements BaseModel +{ + /** @use SdkModel<ProfileShape> */ + use SdkModel; + + /** + * The user's avatar. + */ + #[Optional] + public ?string $avatar; + + /** + * The user's email address. + */ + #[Optional] + public ?string $email; + + /** + * The user's displayname. + */ + #[Optional] + public ?string $name; + + /** + * The user's phone number. + */ + #[Optional] + public ?string $phone; + + /** + * The user's username. + */ + #[Optional] + public ?string $username; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?string $avatar = null, + ?string $email = null, + ?string $name = null, + ?string $phone = null, + ?string $username = null, + ): self { + $self = new self; + + null !== $avatar && $self['avatar'] = $avatar; + null !== $email && $self['email'] = $email; + null !== $name && $self['name'] = $name; + null !== $phone && $self['phone'] = $phone; + null !== $username && $self['username'] = $username; + + return $self; + } + + /** + * The user's avatar. + */ + public function withAvatar(string $avatar): self + { + $self = clone $this; + $self['avatar'] = $avatar; + + return $self; + } + + /** + * The user's email address. + */ + public function withEmail(string $email): self + { + $self = clone $this; + $self['email'] = $email; + + return $self; + } + + /** + * The user's displayname. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * The user's phone number. + */ + public function withPhone(string $phone): self + { + $self = clone $this; + $self['phone'] = $phone; + + return $self; + } + + /** + * The user's username. + */ + public function withUsername(string $username): self + { + $self = clone $this; + $self['username'] = $username; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/State.php b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/State.php new file mode 100644 index 0000000..def3604 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/State.php @@ -0,0 +1,182 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login\State\StateEvent; + +/** + * The connection status of an individual login. + * + * @phpstan-type StateShape = array{ + * stateEvent: StateEvent|value-of<StateEvent>, + * timestamp: float, + * error?: string|null, + * info?: mixed, + * message?: string|null, + * reason?: string|null, + * } + */ +final class State implements BaseModel +{ + /** @use SdkModel<StateShape> */ + use SdkModel; + + /** + * The current state of this login. + * + * @var value-of<StateEvent> $stateEvent + */ + #[Required('state_event', enum: StateEvent::class)] + public string $stateEvent; + + /** + * The time when the state was last updated. + */ + #[Required] + public float $timestamp; + + /** + * An error code defined by the network connector. + */ + #[Optional] + public ?string $error; + + /** + * Additional arbitrary info provided by the network connector. + */ + #[Optional] + public mixed $info; + + /** + * A human-readable error message defined by the network connector. + */ + #[Optional] + public ?string $message; + + /** + * A reason code for non-error states that aren't exactly successes either. + */ + #[Optional] + public ?string $reason; + + /** + * `new State()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * State::with(stateEvent: ..., timestamp: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new State)->withStateEvent(...)->withTimestamp(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param StateEvent|value-of<StateEvent> $stateEvent + */ + public static function with( + StateEvent|string $stateEvent, + float $timestamp, + ?string $error = null, + mixed $info = null, + ?string $message = null, + ?string $reason = null, + ): self { + $self = new self; + + $self['stateEvent'] = $stateEvent; + $self['timestamp'] = $timestamp; + + null !== $error && $self['error'] = $error; + null !== $info && $self['info'] = $info; + null !== $message && $self['message'] = $message; + null !== $reason && $self['reason'] = $reason; + + return $self; + } + + /** + * The current state of this login. + * + * @param StateEvent|value-of<StateEvent> $stateEvent + */ + public function withStateEvent(StateEvent|string $stateEvent): self + { + $self = clone $this; + $self['stateEvent'] = $stateEvent; + + return $self; + } + + /** + * The time when the state was last updated. + */ + public function withTimestamp(float $timestamp): self + { + $self = clone $this; + $self['timestamp'] = $timestamp; + + return $self; + } + + /** + * An error code defined by the network connector. + */ + public function withError(string $error): self + { + $self = clone $this; + $self['error'] = $error; + + return $self; + } + + /** + * Additional arbitrary info provided by the network connector. + */ + public function withInfo(mixed $info): self + { + $self = clone $this; + $self['info'] = $info; + + return $self; + } + + /** + * A human-readable error message defined by the network connector. + */ + public function withMessage(string $message): self + { + $self = clone $this; + $self['message'] = $message; + + return $self; + } + + /** + * A reason code for non-error states that aren't exactly successes either. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/State/StateEvent.php b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/State/StateEvent.php new file mode 100644 index 0000000..1faae90 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Login/State/StateEvent.php @@ -0,0 +1,21 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse\Login\State; + +/** + * The current state of this login. + */ +enum StateEvent: string +{ + case CONNECTING = 'CONNECTING'; + + case CONNECTED = 'CONNECTED'; + + case TRANSIENT_DISCONNECT = 'TRANSIENT_DISCONNECT'; + + case BAD_CREDENTIALS = 'BAD_CREDENTIALS'; + + case UNKNOWN_ERROR = 'UNKNOWN_ERROR'; +} diff --git a/src/Matrix/Bridges/Auth/AuthWhoamiResponse/LoginFlow.php b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/LoginFlow.php new file mode 100644 index 0000000..85010a4 --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/LoginFlow.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * An individual login flow which can be used to sign into the remote network. + * + * @phpstan-type LoginFlowShape = array{ + * id: string, description: string, name: string + * } + */ +final class LoginFlow implements BaseModel +{ + /** @use SdkModel<LoginFlowShape> */ + use SdkModel; + + /** + * An internal ID that is passed to the /login/start call to start a login with this flow. + */ + #[Required] + public string $id; + + /** + * A human-readable description of the login flow. + */ + #[Required] + public string $description; + + /** + * A human-readable name for the login flow. + */ + #[Required] + public string $name; + + /** + * `new LoginFlow()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * LoginFlow::with(id: ..., description: ..., name: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new LoginFlow)->withID(...)->withDescription(...)->withName(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $id, + string $description, + string $name + ): self { + $self = new self; + + $self['id'] = $id; + $self['description'] = $description; + $self['name'] = $name; + + return $self; + } + + /** + * An internal ID that is passed to the /login/start call to start a login with this flow. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * A human-readable description of the login flow. + */ + public function withDescription(string $description): self + { + $self = clone $this; + $self['description'] = $description; + + return $self; + } + + /** + * A human-readable name for the login flow. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Network.php b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Network.php new file mode 100644 index 0000000..922c56f --- /dev/null +++ b/src/Matrix/Bridges/Auth/AuthWhoamiResponse/Network.php @@ -0,0 +1,164 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Info about the network that the bridge is bridging to. + * + * @phpstan-type NetworkShape = array{ + * beeperBridgeType: string, + * displayname: string, + * networkIcon: string, + * networkID: string, + * networkURL: string, + * } + */ +final class Network implements BaseModel +{ + /** @use SdkModel<NetworkShape> */ + use SdkModel; + + /** + * An identifier uniquely identifying the bridge software. + */ + #[Required('beeper_bridge_type')] + public string $beeperBridgeType; + + /** + * The displayname of the network. + */ + #[Required] + public string $displayname; + + /** + * The icon of the network as a `mxc://` URI. + */ + #[Required('network_icon')] + public string $networkIcon; + + /** + * An identifier uniquely identifying the network. + */ + #[Required('network_id')] + public string $networkID; + + /** + * The URL to the website of the network. + */ + #[Required('network_url')] + public string $networkURL; + + /** + * `new Network()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Network::with( + * beeperBridgeType: ..., + * displayname: ..., + * networkIcon: ..., + * networkID: ..., + * networkURL: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Network) + * ->withBeeperBridgeType(...) + * ->withDisplayname(...) + * ->withNetworkIcon(...) + * ->withNetworkID(...) + * ->withNetworkURL(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $beeperBridgeType, + string $displayname, + string $networkIcon, + string $networkID, + string $networkURL, + ): self { + $self = new self; + + $self['beeperBridgeType'] = $beeperBridgeType; + $self['displayname'] = $displayname; + $self['networkIcon'] = $networkIcon; + $self['networkID'] = $networkID; + $self['networkURL'] = $networkURL; + + return $self; + } + + /** + * An identifier uniquely identifying the bridge software. + */ + public function withBeeperBridgeType(string $beeperBridgeType): self + { + $self = clone $this; + $self['beeperBridgeType'] = $beeperBridgeType; + + return $self; + } + + /** + * The displayname of the network. + */ + public function withDisplayname(string $displayname): self + { + $self = clone $this; + $self['displayname'] = $displayname; + + return $self; + } + + /** + * The icon of the network as a `mxc://` URI. + */ + public function withNetworkIcon(string $networkIcon): self + { + $self = clone $this; + $self['networkIcon'] = $networkIcon; + + return $self; + } + + /** + * An identifier uniquely identifying the network. + */ + public function withNetworkID(string $networkID): self + { + $self = clone $this; + $self['networkID'] = $networkID; + + return $self; + } + + /** + * The URL to the website of the network. + */ + public function withNetworkURL(string $networkURL): self + { + $self = clone $this; + $self['networkURL'] = $networkURL; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Contacts/ContactListParams.php b/src/Matrix/Bridges/Contacts/ContactListParams.php new file mode 100644 index 0000000..6ae41eb --- /dev/null +++ b/src/Matrix/Bridges/Contacts/ContactListParams.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Contacts; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Get a list of contacts. + * + * @see BeeperDesktop\Services\Matrix\Bridges\ContactsService::list() + * + * @phpstan-type ContactListParamsShape = array{loginID?: string|null} + */ +final class ContactListParams implements BaseModel +{ + /** @use SdkModel<ContactListParamsShape> */ + use SdkModel; + use SdkParams; + + /** + * An optional explicit login ID to do the action through. + */ + #[Optional] + public ?string $loginID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $loginID = null): self + { + $self = new self; + + null !== $loginID && $self['loginID'] = $loginID; + + return $self; + } + + /** + * An optional explicit login ID to do the action through. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Contacts/ContactListResponse.php b/src/Matrix/Bridges/Contacts/ContactListResponse.php new file mode 100644 index 0000000..0b9b729 --- /dev/null +++ b/src/Matrix/Bridges/Contacts/ContactListResponse.php @@ -0,0 +1,59 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Contacts; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Contacts\ContactListResponse\Contact; + +/** + * @phpstan-import-type ContactShape from \BeeperDesktop\Matrix\Bridges\Contacts\ContactListResponse\Contact + * + * @phpstan-type ContactListResponseShape = array{ + * contacts?: list<Contact|ContactShape>|null + * } + */ +final class ContactListResponse implements BaseModel +{ + /** @use SdkModel<ContactListResponseShape> */ + use SdkModel; + + /** @var list<Contact>|null $contacts */ + #[Optional(list: Contact::class)] + public ?array $contacts; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Contact|ContactShape>|null $contacts + */ + public static function with(?array $contacts = null): self + { + $self = new self; + + null !== $contacts && $self['contacts'] = $contacts; + + return $self; + } + + /** + * @param list<Contact|ContactShape> $contacts + */ + public function withContacts(array $contacts): self + { + $self = clone $this; + $self['contacts'] = $contacts; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Contacts/ContactListResponse/Contact.php b/src/Matrix/Bridges/Contacts/ContactListResponse/Contact.php new file mode 100644 index 0000000..3164e65 --- /dev/null +++ b/src/Matrix/Bridges/Contacts/ContactListResponse/Contact.php @@ -0,0 +1,181 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Contacts\ContactListResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * A successfully resolved identifier. + * + * @phpstan-type ContactShape = array{ + * id: string, + * avatarURL?: string|null, + * dmRoomMxid?: string|null, + * identifiers?: list<string>|null, + * mxid?: string|null, + * name?: string|null, + * } + */ +final class Contact implements BaseModel +{ + /** @use SdkModel<ContactShape> */ + use SdkModel; + + /** + * The internal user ID of the resolved user. + */ + #[Required] + public string $id; + + /** + * The avatar of the user on the remote network. + */ + #[Optional('avatar_url')] + public ?string $avatarURL; + + /** + * The Matrix room ID of the direct chat with the user. + */ + #[Optional('dm_room_mxid')] + public ?string $dmRoomMxid; + + /** + * A list of identifiers for the user on the remote network. + * + * @var list<string>|null $identifiers + */ + #[Optional(list: 'string')] + public ?array $identifiers; + + /** + * The Matrix user ID of the ghost representing the user. + */ + #[Optional] + public ?string $mxid; + + /** + * The name of the user on the remote network. + */ + #[Optional] + public ?string $name; + + /** + * `new Contact()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Contact::with(id: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Contact)->withID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<string>|null $identifiers + */ + public static function with( + string $id, + ?string $avatarURL = null, + ?string $dmRoomMxid = null, + ?array $identifiers = null, + ?string $mxid = null, + ?string $name = null, + ): self { + $self = new self; + + $self['id'] = $id; + + null !== $avatarURL && $self['avatarURL'] = $avatarURL; + null !== $dmRoomMxid && $self['dmRoomMxid'] = $dmRoomMxid; + null !== $identifiers && $self['identifiers'] = $identifiers; + null !== $mxid && $self['mxid'] = $mxid; + null !== $name && $self['name'] = $name; + + return $self; + } + + /** + * The internal user ID of the resolved user. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * The avatar of the user on the remote network. + */ + public function withAvatarURL(string $avatarURL): self + { + $self = clone $this; + $self['avatarURL'] = $avatarURL; + + return $self; + } + + /** + * The Matrix room ID of the direct chat with the user. + */ + public function withDmRoomMxid(string $dmRoomMxid): self + { + $self = clone $this; + $self['dmRoomMxid'] = $dmRoomMxid; + + return $self; + } + + /** + * A list of identifiers for the user on the remote network. + * + * @param list<string> $identifiers + */ + public function withIdentifiers(array $identifiers): self + { + $self = clone $this; + $self['identifiers'] = $identifiers; + + return $self; + } + + /** + * The Matrix user ID of the ghost representing the user. + */ + public function withMxid(string $mxid): self + { + $self = clone $this; + $self['mxid'] = $mxid; + + return $self; + } + + /** + * The name of the user on the remote network. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Rooms/RoomCreateDmParams.php b/src/Matrix/Bridges/Rooms/RoomCreateDmParams.php new file mode 100644 index 0000000..72e3113 --- /dev/null +++ b/src/Matrix/Bridges/Rooms/RoomCreateDmParams.php @@ -0,0 +1,90 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Rooms; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Create a direct chat with a user on the remote network. + * + * @see BeeperDesktop\Services\Matrix\Bridges\RoomsService::createDm() + * + * @phpstan-type RoomCreateDmParamsShape = array{ + * bridgeID: string, loginID?: string|null + * } + */ +final class RoomCreateDmParams implements BaseModel +{ + /** @use SdkModel<RoomCreateDmParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $bridgeID; + + /** + * An optional explicit login ID to do the action through. + */ + #[Optional] + public ?string $loginID; + + /** + * `new RoomCreateDmParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RoomCreateDmParams::with(bridgeID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RoomCreateDmParams)->withBridgeID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $bridgeID, ?string $loginID = null): self + { + $self = new self; + + $self['bridgeID'] = $bridgeID; + + null !== $loginID && $self['loginID'] = $loginID; + + return $self; + } + + public function withBridgeID(string $bridgeID): self + { + $self = clone $this; + $self['bridgeID'] = $bridgeID; + + return $self; + } + + /** + * An optional explicit login ID to do the action through. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Rooms/RoomCreateGroupParams.php b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams.php new file mode 100644 index 0000000..e008ab0 --- /dev/null +++ b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams.php @@ -0,0 +1,296 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Rooms; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Avatar; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Disappear; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Name; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Topic; + +/** + * Create a group chat on the remote network. + * + * @see BeeperDesktop\Services\Matrix\Bridges\RoomsService::createGroup() + * + * @phpstan-import-type AvatarShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Avatar + * @phpstan-import-type DisappearShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Disappear + * @phpstan-import-type NameShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Name + * @phpstan-import-type TopicShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Topic + * + * @phpstan-type RoomCreateGroupParamsShape = array{ + * bridgeID: string, + * loginID?: string|null, + * avatar?: null|Avatar|AvatarShape, + * disappear?: null|Disappear|DisappearShape, + * name?: null|Name|NameShape, + * parent?: mixed, + * participants?: list<string>|null, + * roomID?: string|null, + * topic?: null|Topic|TopicShape, + * type?: string|null, + * username?: string|null, + * } + */ +final class RoomCreateGroupParams implements BaseModel +{ + /** @use SdkModel<RoomCreateGroupParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $bridgeID; + + /** + * An optional explicit login ID to do the action through. + */ + #[Optional] + public ?string $loginID; + + /** + * The `m.room.avatar` event content for the room. + */ + #[Optional] + public ?Avatar $avatar; + + /** + * The `com.beeper.disappearing_timer` event content for the room. + */ + #[Optional] + public ?Disappear $disappear; + + /** + * The `m.room.name` event content for the room. + */ + #[Optional] + public ?Name $name; + + #[Optional] + public mixed $parent; + + /** + * The users to add to the group initially. + * + * @var list<string>|null $participants + */ + #[Optional(list: 'string')] + public ?array $participants; + + /** + * An existing Matrix room ID to bridge to. + * The other parameters must be already in sync with the room state when using this parameter. + */ + #[Optional('room_id')] + public ?string $roomID; + + /** + * The `m.room.topic` event content for the room. + */ + #[Optional] + public ?Topic $topic; + + /** + * The type of group to create. + */ + #[Optional] + public ?string $type; + + /** + * The public username for the created group. + */ + #[Optional] + public ?string $username; + + /** + * `new RoomCreateGroupParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RoomCreateGroupParams::with(bridgeID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RoomCreateGroupParams)->withBridgeID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Avatar|AvatarShape|null $avatar + * @param Disappear|DisappearShape|null $disappear + * @param Name|NameShape|null $name + * @param list<string>|null $participants + * @param Topic|TopicShape|null $topic + */ + public static function with( + string $bridgeID, + ?string $loginID = null, + Avatar|array|null $avatar = null, + Disappear|array|null $disappear = null, + Name|array|null $name = null, + mixed $parent = null, + ?array $participants = null, + ?string $roomID = null, + Topic|array|null $topic = null, + ?string $type = null, + ?string $username = null, + ): self { + $self = new self; + + $self['bridgeID'] = $bridgeID; + + null !== $loginID && $self['loginID'] = $loginID; + null !== $avatar && $self['avatar'] = $avatar; + null !== $disappear && $self['disappear'] = $disappear; + null !== $name && $self['name'] = $name; + null !== $parent && $self['parent'] = $parent; + null !== $participants && $self['participants'] = $participants; + null !== $roomID && $self['roomID'] = $roomID; + null !== $topic && $self['topic'] = $topic; + null !== $type && $self['type'] = $type; + null !== $username && $self['username'] = $username; + + return $self; + } + + public function withBridgeID(string $bridgeID): self + { + $self = clone $this; + $self['bridgeID'] = $bridgeID; + + return $self; + } + + /** + * An optional explicit login ID to do the action through. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * The `m.room.avatar` event content for the room. + * + * @param Avatar|AvatarShape $avatar + */ + public function withAvatar(Avatar|array $avatar): self + { + $self = clone $this; + $self['avatar'] = $avatar; + + return $self; + } + + /** + * The `com.beeper.disappearing_timer` event content for the room. + * + * @param Disappear|DisappearShape $disappear + */ + public function withDisappear(Disappear|array $disappear): self + { + $self = clone $this; + $self['disappear'] = $disappear; + + return $self; + } + + /** + * The `m.room.name` event content for the room. + * + * @param Name|NameShape $name + */ + public function withName(Name|array $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + public function withParent(mixed $parent): self + { + $self = clone $this; + $self['parent'] = $parent; + + return $self; + } + + /** + * The users to add to the group initially. + * + * @param list<string> $participants + */ + public function withParticipants(array $participants): self + { + $self = clone $this; + $self['participants'] = $participants; + + return $self; + } + + /** + * An existing Matrix room ID to bridge to. + * The other parameters must be already in sync with the room state when using this parameter. + */ + public function withRoomID(string $roomID): self + { + $self = clone $this; + $self['roomID'] = $roomID; + + return $self; + } + + /** + * The `m.room.topic` event content for the room. + * + * @param Topic|TopicShape $topic + */ + public function withTopic(Topic|array $topic): self + { + $self = clone $this; + $self['topic'] = $topic; + + return $self; + } + + /** + * The type of group to create. + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * The public username for the created group. + */ + public function withUsername(string $username): self + { + $self = clone $this; + $self['username'] = $username; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Avatar.php b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Avatar.php new file mode 100644 index 0000000..63eccf0 --- /dev/null +++ b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Avatar.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * The `m.room.avatar` event content for the room. + * + * @phpstan-type AvatarShape = array{url?: string|null} + */ +final class Avatar implements BaseModel +{ + /** @use SdkModel<AvatarShape> */ + use SdkModel; + + #[Optional] + public ?string $url; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $url = null): self + { + $self = new self; + + null !== $url && $self['url'] = $url; + + return $self; + } + + public function withURL(string $url): self + { + $self = clone $this; + $self['url'] = $url; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Disappear.php b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Disappear.php new file mode 100644 index 0000000..13f7500 --- /dev/null +++ b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Disappear.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * The `com.beeper.disappearing_timer` event content for the room. + * + * @phpstan-type DisappearShape = array{timer?: float|null, type?: string|null} + */ +final class Disappear implements BaseModel +{ + /** @use SdkModel<DisappearShape> */ + use SdkModel; + + #[Optional] + public ?float $timer; + + #[Optional] + public ?string $type; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?float $timer = null, ?string $type = null): self + { + $self = new self; + + null !== $timer && $self['timer'] = $timer; + null !== $type && $self['type'] = $type; + + return $self; + } + + public function withTimer(float $timer): self + { + $self = clone $this; + $self['timer'] = $timer; + + return $self; + } + + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Name.php b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Name.php new file mode 100644 index 0000000..fadacff --- /dev/null +++ b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Name.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * The `m.room.name` event content for the room. + * + * @phpstan-type NameShape = array{name?: string|null} + */ +final class Name implements BaseModel +{ + /** @use SdkModel<NameShape> */ + use SdkModel; + + #[Optional] + public ?string $name; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $name = null): self + { + $self = new self; + + null !== $name && $self['name'] = $name; + + return $self; + } + + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Topic.php b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Topic.php new file mode 100644 index 0000000..d4bb1fc --- /dev/null +++ b/src/Matrix/Bridges/Rooms/RoomCreateGroupParams/Topic.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * The `m.room.topic` event content for the room. + * + * @phpstan-type TopicShape = array{topic?: string|null} + */ +final class Topic implements BaseModel +{ + /** @use SdkModel<TopicShape> */ + use SdkModel; + + #[Optional] + public ?string $topic; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $topic = null): self + { + $self = new self; + + null !== $topic && $self['topic'] = $topic; + + return $self; + } + + public function withTopic(string $topic): self + { + $self = clone $this; + $self['topic'] = $topic; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Rooms/RoomNewDmResponse.php b/src/Matrix/Bridges/Rooms/RoomNewDmResponse.php new file mode 100644 index 0000000..2575049 --- /dev/null +++ b/src/Matrix/Bridges/Rooms/RoomNewDmResponse.php @@ -0,0 +1,181 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Rooms; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * A successfully resolved identifier. + * + * @phpstan-type RoomNewDmResponseShape = array{ + * id: string, + * avatarURL?: string|null, + * dmRoomMxid?: string|null, + * identifiers?: list<string>|null, + * mxid?: string|null, + * name?: string|null, + * } + */ +final class RoomNewDmResponse implements BaseModel +{ + /** @use SdkModel<RoomNewDmResponseShape> */ + use SdkModel; + + /** + * The internal user ID of the resolved user. + */ + #[Required] + public string $id; + + /** + * The avatar of the user on the remote network. + */ + #[Optional('avatar_url')] + public ?string $avatarURL; + + /** + * The Matrix room ID of the direct chat with the user. + */ + #[Optional('dm_room_mxid')] + public ?string $dmRoomMxid; + + /** + * A list of identifiers for the user on the remote network. + * + * @var list<string>|null $identifiers + */ + #[Optional(list: 'string')] + public ?array $identifiers; + + /** + * The Matrix user ID of the ghost representing the user. + */ + #[Optional] + public ?string $mxid; + + /** + * The name of the user on the remote network. + */ + #[Optional] + public ?string $name; + + /** + * `new RoomNewDmResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RoomNewDmResponse::with(id: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RoomNewDmResponse)->withID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<string>|null $identifiers + */ + public static function with( + string $id, + ?string $avatarURL = null, + ?string $dmRoomMxid = null, + ?array $identifiers = null, + ?string $mxid = null, + ?string $name = null, + ): self { + $self = new self; + + $self['id'] = $id; + + null !== $avatarURL && $self['avatarURL'] = $avatarURL; + null !== $dmRoomMxid && $self['dmRoomMxid'] = $dmRoomMxid; + null !== $identifiers && $self['identifiers'] = $identifiers; + null !== $mxid && $self['mxid'] = $mxid; + null !== $name && $self['name'] = $name; + + return $self; + } + + /** + * The internal user ID of the resolved user. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * The avatar of the user on the remote network. + */ + public function withAvatarURL(string $avatarURL): self + { + $self = clone $this; + $self['avatarURL'] = $avatarURL; + + return $self; + } + + /** + * The Matrix room ID of the direct chat with the user. + */ + public function withDmRoomMxid(string $dmRoomMxid): self + { + $self = clone $this; + $self['dmRoomMxid'] = $dmRoomMxid; + + return $self; + } + + /** + * A list of identifiers for the user on the remote network. + * + * @param list<string> $identifiers + */ + public function withIdentifiers(array $identifiers): self + { + $self = clone $this; + $self['identifiers'] = $identifiers; + + return $self; + } + + /** + * The Matrix user ID of the ghost representing the user. + */ + public function withMxid(string $mxid): self + { + $self = clone $this; + $self['mxid'] = $mxid; + + return $self; + } + + /** + * The name of the user on the remote network. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Rooms/RoomNewGroupResponse.php b/src/Matrix/Bridges/Rooms/RoomNewGroupResponse.php new file mode 100644 index 0000000..900771e --- /dev/null +++ b/src/Matrix/Bridges/Rooms/RoomNewGroupResponse.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Rooms; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * A successfully created group chat. + * + * @phpstan-type RoomNewGroupResponseShape = array{id: string, mxid: string} + */ +final class RoomNewGroupResponse implements BaseModel +{ + /** @use SdkModel<RoomNewGroupResponseShape> */ + use SdkModel; + + /** + * The internal chat ID of the created group. + */ + #[Required] + public string $id; + + /** + * The Matrix room ID of the portal. + */ + #[Required] + public string $mxid; + + /** + * `new RoomNewGroupResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RoomNewGroupResponse::with(id: ..., mxid: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RoomNewGroupResponse)->withID(...)->withMxid(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $id, string $mxid): self + { + $self = new self; + + $self['id'] = $id; + $self['mxid'] = $mxid; + + return $self; + } + + /** + * The internal chat ID of the created group. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * The Matrix room ID of the portal. + */ + public function withMxid(string $mxid): self + { + $self = clone $this; + $self['mxid'] = $mxid; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Users/UserResolveParams.php b/src/Matrix/Bridges/Users/UserResolveParams.php new file mode 100644 index 0000000..8e53472 --- /dev/null +++ b/src/Matrix/Bridges/Users/UserResolveParams.php @@ -0,0 +1,90 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Users; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Resolve an identifier to a user on the remote network. + * + * @see BeeperDesktop\Services\Matrix\Bridges\UsersService::resolve() + * + * @phpstan-type UserResolveParamsShape = array{ + * bridgeID: string, loginID?: string|null + * } + */ +final class UserResolveParams implements BaseModel +{ + /** @use SdkModel<UserResolveParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $bridgeID; + + /** + * An optional explicit login ID to do the action through. + */ + #[Optional] + public ?string $loginID; + + /** + * `new UserResolveParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UserResolveParams::with(bridgeID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UserResolveParams)->withBridgeID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $bridgeID, ?string $loginID = null): self + { + $self = new self; + + $self['bridgeID'] = $bridgeID; + + null !== $loginID && $self['loginID'] = $loginID; + + return $self; + } + + public function withBridgeID(string $bridgeID): self + { + $self = clone $this; + $self['bridgeID'] = $bridgeID; + + return $self; + } + + /** + * An optional explicit login ID to do the action through. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Users/UserResolveResponse.php b/src/Matrix/Bridges/Users/UserResolveResponse.php new file mode 100644 index 0000000..e0dd5b9 --- /dev/null +++ b/src/Matrix/Bridges/Users/UserResolveResponse.php @@ -0,0 +1,181 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Users; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * A successfully resolved identifier. + * + * @phpstan-type UserResolveResponseShape = array{ + * id: string, + * avatarURL?: string|null, + * dmRoomMxid?: string|null, + * identifiers?: list<string>|null, + * mxid?: string|null, + * name?: string|null, + * } + */ +final class UserResolveResponse implements BaseModel +{ + /** @use SdkModel<UserResolveResponseShape> */ + use SdkModel; + + /** + * The internal user ID of the resolved user. + */ + #[Required] + public string $id; + + /** + * The avatar of the user on the remote network. + */ + #[Optional('avatar_url')] + public ?string $avatarURL; + + /** + * The Matrix room ID of the direct chat with the user. + */ + #[Optional('dm_room_mxid')] + public ?string $dmRoomMxid; + + /** + * A list of identifiers for the user on the remote network. + * + * @var list<string>|null $identifiers + */ + #[Optional(list: 'string')] + public ?array $identifiers; + + /** + * The Matrix user ID of the ghost representing the user. + */ + #[Optional] + public ?string $mxid; + + /** + * The name of the user on the remote network. + */ + #[Optional] + public ?string $name; + + /** + * `new UserResolveResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * UserResolveResponse::with(id: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new UserResolveResponse)->withID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<string>|null $identifiers + */ + public static function with( + string $id, + ?string $avatarURL = null, + ?string $dmRoomMxid = null, + ?array $identifiers = null, + ?string $mxid = null, + ?string $name = null, + ): self { + $self = new self; + + $self['id'] = $id; + + null !== $avatarURL && $self['avatarURL'] = $avatarURL; + null !== $dmRoomMxid && $self['dmRoomMxid'] = $dmRoomMxid; + null !== $identifiers && $self['identifiers'] = $identifiers; + null !== $mxid && $self['mxid'] = $mxid; + null !== $name && $self['name'] = $name; + + return $self; + } + + /** + * The internal user ID of the resolved user. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * The avatar of the user on the remote network. + */ + public function withAvatarURL(string $avatarURL): self + { + $self = clone $this; + $self['avatarURL'] = $avatarURL; + + return $self; + } + + /** + * The Matrix room ID of the direct chat with the user. + */ + public function withDmRoomMxid(string $dmRoomMxid): self + { + $self = clone $this; + $self['dmRoomMxid'] = $dmRoomMxid; + + return $self; + } + + /** + * A list of identifiers for the user on the remote network. + * + * @param list<string> $identifiers + */ + public function withIdentifiers(array $identifiers): self + { + $self = clone $this; + $self['identifiers'] = $identifiers; + + return $self; + } + + /** + * The Matrix user ID of the ghost representing the user. + */ + public function withMxid(string $mxid): self + { + $self = clone $this; + $self['mxid'] = $mxid; + + return $self; + } + + /** + * The name of the user on the remote network. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Users/UserSearchParams.php b/src/Matrix/Bridges/Users/UserSearchParams.php new file mode 100644 index 0000000..9032b90 --- /dev/null +++ b/src/Matrix/Bridges/Users/UserSearchParams.php @@ -0,0 +1,82 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Users; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Search for users on the remote network. + * + * @see BeeperDesktop\Services\Matrix\Bridges\UsersService::search() + * + * @phpstan-type UserSearchParamsShape = array{ + * loginID?: string|null, query?: string|null + * } + */ +final class UserSearchParams implements BaseModel +{ + /** @use SdkModel<UserSearchParamsShape> */ + use SdkModel; + use SdkParams; + + /** + * An optional explicit login ID to do the action through. + */ + #[Optional] + public ?string $loginID; + + /** + * The search query to send to the remote network. + */ + #[Optional] + public ?string $query; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?string $loginID = null, + ?string $query = null + ): self { + $self = new self; + + null !== $loginID && $self['loginID'] = $loginID; + null !== $query && $self['query'] = $query; + + return $self; + } + + /** + * An optional explicit login ID to do the action through. + */ + public function withLoginID(string $loginID): self + { + $self = clone $this; + $self['loginID'] = $loginID; + + return $self; + } + + /** + * The search query to send to the remote network. + */ + public function withQuery(string $query): self + { + $self = clone $this; + $self['query'] = $query; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Users/UserSearchResponse.php b/src/Matrix/Bridges/Users/UserSearchResponse.php new file mode 100644 index 0000000..5db0827 --- /dev/null +++ b/src/Matrix/Bridges/Users/UserSearchResponse.php @@ -0,0 +1,59 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Users; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Bridges\Users\UserSearchResponse\Result; + +/** + * @phpstan-import-type ResultShape from \BeeperDesktop\Matrix\Bridges\Users\UserSearchResponse\Result + * + * @phpstan-type UserSearchResponseShape = array{ + * results?: list<Result|ResultShape>|null + * } + */ +final class UserSearchResponse implements BaseModel +{ + /** @use SdkModel<UserSearchResponseShape> */ + use SdkModel; + + /** @var list<Result>|null $results */ + #[Optional(list: Result::class)] + public ?array $results; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<Result|ResultShape>|null $results + */ + public static function with(?array $results = null): self + { + $self = new self; + + null !== $results && $self['results'] = $results; + + return $self; + } + + /** + * @param list<Result|ResultShape> $results + */ + public function withResults(array $results): self + { + $self = clone $this; + $self['results'] = $results; + + return $self; + } +} diff --git a/src/Matrix/Bridges/Users/UserSearchResponse/Result.php b/src/Matrix/Bridges/Users/UserSearchResponse/Result.php new file mode 100644 index 0000000..84a8caa --- /dev/null +++ b/src/Matrix/Bridges/Users/UserSearchResponse/Result.php @@ -0,0 +1,181 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Bridges\Users\UserSearchResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * A successfully resolved identifier. + * + * @phpstan-type ResultShape = array{ + * id: string, + * avatarURL?: string|null, + * dmRoomMxid?: string|null, + * identifiers?: list<string>|null, + * mxid?: string|null, + * name?: string|null, + * } + */ +final class Result implements BaseModel +{ + /** @use SdkModel<ResultShape> */ + use SdkModel; + + /** + * The internal user ID of the resolved user. + */ + #[Required] + public string $id; + + /** + * The avatar of the user on the remote network. + */ + #[Optional('avatar_url')] + public ?string $avatarURL; + + /** + * The Matrix room ID of the direct chat with the user. + */ + #[Optional('dm_room_mxid')] + public ?string $dmRoomMxid; + + /** + * A list of identifiers for the user on the remote network. + * + * @var list<string>|null $identifiers + */ + #[Optional(list: 'string')] + public ?array $identifiers; + + /** + * The Matrix user ID of the ghost representing the user. + */ + #[Optional] + public ?string $mxid; + + /** + * The name of the user on the remote network. + */ + #[Optional] + public ?string $name; + + /** + * `new Result()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Result::with(id: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Result)->withID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<string>|null $identifiers + */ + public static function with( + string $id, + ?string $avatarURL = null, + ?string $dmRoomMxid = null, + ?array $identifiers = null, + ?string $mxid = null, + ?string $name = null, + ): self { + $self = new self; + + $self['id'] = $id; + + null !== $avatarURL && $self['avatarURL'] = $avatarURL; + null !== $dmRoomMxid && $self['dmRoomMxid'] = $dmRoomMxid; + null !== $identifiers && $self['identifiers'] = $identifiers; + null !== $mxid && $self['mxid'] = $mxid; + null !== $name && $self['name'] = $name; + + return $self; + } + + /** + * The internal user ID of the resolved user. + */ + public function withID(string $id): self + { + $self = clone $this; + $self['id'] = $id; + + return $self; + } + + /** + * The avatar of the user on the remote network. + */ + public function withAvatarURL(string $avatarURL): self + { + $self = clone $this; + $self['avatarURL'] = $avatarURL; + + return $self; + } + + /** + * The Matrix room ID of the direct chat with the user. + */ + public function withDmRoomMxid(string $dmRoomMxid): self + { + $self = clone $this; + $self['dmRoomMxid'] = $dmRoomMxid; + + return $self; + } + + /** + * A list of identifiers for the user on the remote network. + * + * @param list<string> $identifiers + */ + public function withIdentifiers(array $identifiers): self + { + $self = clone $this; + $self['identifiers'] = $identifiers; + + return $self; + } + + /** + * The Matrix user ID of the ghost representing the user. + */ + public function withMxid(string $mxid): self + { + $self = clone $this; + $self['mxid'] = $mxid; + + return $self; + } + + /** + * The name of the user on the remote network. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } +} diff --git a/src/Matrix/Rooms/AccountData/AccountDataRetrieveParams.php b/src/Matrix/Rooms/AccountData/AccountDataRetrieveParams.php new file mode 100644 index 0000000..7d2b0f2 --- /dev/null +++ b/src/Matrix/Rooms/AccountData/AccountDataRetrieveParams.php @@ -0,0 +1,83 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\AccountData; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Get some account data for the client on a given room. This config is only + * visible to the user that set the account data. + * + * @see BeeperDesktop\Services\Matrix\Rooms\AccountDataService::retrieve() + * + * @phpstan-type AccountDataRetrieveParamsShape = array{ + * userID: string, roomID: string + * } + */ +final class AccountDataRetrieveParams implements BaseModel +{ + /** @use SdkModel<AccountDataRetrieveParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $userID; + + #[Required] + public string $roomID; + + /** + * `new AccountDataRetrieveParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AccountDataRetrieveParams::with(userID: ..., roomID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AccountDataRetrieveParams)->withUserID(...)->withRoomID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $userID, string $roomID): self + { + $self = new self; + + $self['userID'] = $userID; + $self['roomID'] = $roomID; + + return $self; + } + + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } + + public function withRoomID(string $roomID): self + { + $self = clone $this; + $self['roomID'] = $roomID; + + return $self; + } +} diff --git a/src/Matrix/Rooms/AccountData/AccountDataUpdateParams.php b/src/Matrix/Rooms/AccountData/AccountDataUpdateParams.php new file mode 100644 index 0000000..60da214 --- /dev/null +++ b/src/Matrix/Rooms/AccountData/AccountDataUpdateParams.php @@ -0,0 +1,99 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\AccountData; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * 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). + * + * @see BeeperDesktop\Services\Matrix\Rooms\AccountDataService::update() + * + * @phpstan-type AccountDataUpdateParamsShape = array{ + * userID: string, roomID: string, body: mixed + * } + */ +final class AccountDataUpdateParams implements BaseModel +{ + /** @use SdkModel<AccountDataUpdateParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $userID; + + #[Required] + public string $roomID; + + #[Required] + public mixed $body; + + /** + * `new AccountDataUpdateParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AccountDataUpdateParams::with(userID: ..., roomID: ..., body: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AccountDataUpdateParams)->withUserID(...)->withRoomID(...)->withBody(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $userID, + string $roomID, + mixed $body + ): self { + $self = new self; + + $self['userID'] = $userID; + $self['roomID'] = $roomID; + $self['body'] = $body; + + return $self; + } + + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } + + public function withRoomID(string $roomID): self + { + $self = clone $this; + $self['roomID'] = $roomID; + + return $self; + } + + public function withBody(mixed $body): self + { + $self = clone $this; + $self['body'] = $body; + + return $self; + } +} diff --git a/src/Matrix/Rooms/Events/EventGetResponse.php b/src/Matrix/Rooms/Events/EventGetResponse.php new file mode 100644 index 0000000..8380723 --- /dev/null +++ b/src/Matrix/Rooms/Events/EventGetResponse.php @@ -0,0 +1,245 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\Events; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Rooms\Events\EventGetResponse\Unsigned; + +/** + * 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. + * + * @phpstan-import-type UnsignedShape from \BeeperDesktop\Matrix\Rooms\Events\EventGetResponse\Unsigned + * + * @phpstan-type EventGetResponseShape = array{ + * content: mixed, + * eventID: string, + * originServerTs: int, + * roomID: string, + * sender: string, + * type: string, + * stateKey?: string|null, + * unsigned?: null|Unsigned|UnsignedShape, + * } + */ +final class EventGetResponse implements BaseModel +{ + /** @use SdkModel<EventGetResponseShape> */ + use SdkModel; + + /** + * The body of this event, as created by the client which sent it. + */ + #[Required] + public mixed $content; + + /** + * The globally unique identifier for this event. + */ + #[Required('event_id')] + public string $eventID; + + /** + * Timestamp (in milliseconds since the unix epoch) on originating homeserver + * when this event was sent. + */ + #[Required('origin_server_ts')] + public int $originServerTs; + + /** + * The ID of the room associated with this event. + */ + #[Required('room_id')] + public string $roomID; + + /** + * Contains the fully-qualified ID of the user who sent this event. + */ + #[Required] + public string $sender; + + /** + * The type of the event. + */ + #[Required] + public string $type; + + /** + * 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. + */ + #[Optional('state_key')] + public ?string $stateKey; + + #[Optional] + public ?Unsigned $unsigned; + + /** + * `new EventGetResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * EventGetResponse::with( + * content: ..., + * eventID: ..., + * originServerTs: ..., + * roomID: ..., + * sender: ..., + * type: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new EventGetResponse) + * ->withContent(...) + * ->withEventID(...) + * ->withOriginServerTs(...) + * ->withRoomID(...) + * ->withSender(...) + * ->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Unsigned|UnsignedShape|null $unsigned + */ + public static function with( + mixed $content, + string $eventID, + int $originServerTs, + string $roomID, + string $sender, + string $type, + ?string $stateKey = null, + Unsigned|array|null $unsigned = null, + ): self { + $self = new self; + + $self['content'] = $content; + $self['eventID'] = $eventID; + $self['originServerTs'] = $originServerTs; + $self['roomID'] = $roomID; + $self['sender'] = $sender; + $self['type'] = $type; + + null !== $stateKey && $self['stateKey'] = $stateKey; + null !== $unsigned && $self['unsigned'] = $unsigned; + + return $self; + } + + /** + * The body of this event, as created by the client which sent it. + */ + public function withContent(mixed $content): self + { + $self = clone $this; + $self['content'] = $content; + + return $self; + } + + /** + * The globally unique identifier for this event. + */ + public function withEventID(string $eventID): self + { + $self = clone $this; + $self['eventID'] = $eventID; + + return $self; + } + + /** + * Timestamp (in milliseconds since the unix epoch) on originating homeserver + * when this event was sent. + */ + public function withOriginServerTs(int $originServerTs): self + { + $self = clone $this; + $self['originServerTs'] = $originServerTs; + + return $self; + } + + /** + * The ID of the room associated with this event. + */ + public function withRoomID(string $roomID): self + { + $self = clone $this; + $self['roomID'] = $roomID; + + return $self; + } + + /** + * Contains the fully-qualified ID of the user who sent this event. + */ + public function withSender(string $sender): self + { + $self = clone $this; + $self['sender'] = $sender; + + return $self; + } + + /** + * The type of the event. + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * 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. + */ + public function withStateKey(string $stateKey): self + { + $self = clone $this; + $self['stateKey'] = $stateKey; + + return $self; + } + + /** + * @param Unsigned|UnsignedShape $unsigned + */ + public function withUnsigned(Unsigned|array $unsigned): self + { + $self = clone $this; + $self['unsigned'] = $unsigned; + + return $self; + } +} diff --git a/src/Matrix/Rooms/Events/EventGetResponse/Unsigned.php b/src/Matrix/Rooms/Events/EventGetResponse/Unsigned.php new file mode 100644 index 0000000..d10f617 --- /dev/null +++ b/src/Matrix/Rooms/Events/EventGetResponse/Unsigned.php @@ -0,0 +1,167 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\Events\EventGetResponse; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-type UnsignedShape = array{ + * age?: int|null, + * membership?: string|null, + * prevContent?: mixed, + * redactedBecause?: mixed, + * transactionID?: string|null, + * } + */ +final class Unsigned implements BaseModel +{ + /** @use SdkModel<UnsignedShape> */ + use SdkModel; + + /** + * 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. + */ + #[Optional] + public ?int $age; + + /** + * 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"). + */ + #[Optional] + public ?string $membership; + + /** + * 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. + */ + #[Optional('prev_content')] + public mixed $prevContent; + + #[Optional('redacted_because')] + public mixed $redactedBecause; + + /** + * 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. + */ + #[Optional('transaction_id')] + public ?string $transactionID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?int $age = null, + ?string $membership = null, + mixed $prevContent = null, + mixed $redactedBecause = null, + ?string $transactionID = null, + ): self { + $self = new self; + + null !== $age && $self['age'] = $age; + null !== $membership && $self['membership'] = $membership; + null !== $prevContent && $self['prevContent'] = $prevContent; + null !== $redactedBecause && $self['redactedBecause'] = $redactedBecause; + null !== $transactionID && $self['transactionID'] = $transactionID; + + return $self; + } + + /** + * 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. + */ + public function withAge(int $age): self + { + $self = clone $this; + $self['age'] = $age; + + return $self; + } + + /** + * 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"). + */ + public function withMembership(string $membership): self + { + $self = clone $this; + $self['membership'] = $membership; + + return $self; + } + + /** + * 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. + */ + public function withPrevContent(mixed $prevContent): self + { + $self = clone $this; + $self['prevContent'] = $prevContent; + + return $self; + } + + public function withRedactedBecause(mixed $redactedBecause): self + { + $self = clone $this; + $self['redactedBecause'] = $redactedBecause; + + return $self; + } + + /** + * 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. + */ + public function withTransactionID(string $transactionID): self + { + $self = clone $this; + $self['transactionID'] = $transactionID; + + return $self; + } +} diff --git a/src/Matrix/Rooms/Events/EventRetrieveParams.php b/src/Matrix/Rooms/Events/EventRetrieveParams.php new file mode 100644 index 0000000..08f2b27 --- /dev/null +++ b/src/Matrix/Rooms/Events/EventRetrieveParams.php @@ -0,0 +1,69 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\Events; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * 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. + * + * @see BeeperDesktop\Services\Matrix\Rooms\EventsService::retrieve() + * + * @phpstan-type EventRetrieveParamsShape = array{roomID: string} + */ +final class EventRetrieveParams implements BaseModel +{ + /** @use SdkModel<EventRetrieveParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $roomID; + + /** + * `new EventRetrieveParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * EventRetrieveParams::with(roomID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new EventRetrieveParams)->withRoomID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $roomID): self + { + $self = new self; + + $self['roomID'] = $roomID; + + return $self; + } + + public function withRoomID(string $roomID): self + { + $self = clone $this; + $self['roomID'] = $roomID; + + return $self; + } +} diff --git a/src/Matrix/Rooms/RoomCreateParams.php b/src/Matrix/Rooms/RoomCreateParams.php new file mode 100644 index 0000000..115ecf7 --- /dev/null +++ b/src/Matrix/Rooms/RoomCreateParams.php @@ -0,0 +1,471 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\InitialState; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Invite3pid; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Preset; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Visibility; + +/** + * 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`. + * + * @see BeeperDesktop\Services\Matrix\RoomsService::create() + * + * @phpstan-import-type InitialStateShape from \BeeperDesktop\Matrix\Rooms\RoomCreateParams\InitialState + * @phpstan-import-type Invite3pidShape from \BeeperDesktop\Matrix\Rooms\RoomCreateParams\Invite3pid + * + * @phpstan-type RoomCreateParamsShape = array{ + * creationContent?: mixed, + * initialState?: list<InitialState|InitialStateShape>|null, + * invite?: list<string>|null, + * invite3pid?: list<Invite3pid|Invite3pidShape>|null, + * isDirect?: bool|null, + * name?: string|null, + * powerLevelContentOverride?: mixed, + * preset?: null|Preset|value-of<Preset>, + * roomAliasName?: string|null, + * roomVersion?: string|null, + * topic?: string|null, + * visibility?: null|Visibility|value-of<Visibility>, + * } + */ +final class RoomCreateParams implements BaseModel +{ + /** @use SdkModel<RoomCreateParamsShape> */ + use SdkModel; + use SdkParams; + + /** + * 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. + */ + #[Optional('creation_content')] + public mixed $creationContent; + + /** + * 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. + * + * @var list<InitialState>|null $initialState + */ + #[Optional('initial_state', list: InitialState::class)] + public ?array $initialState; + + /** + * 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. + * + * @var list<string>|null $invite + */ + #[Optional(list: 'string')] + public ?array $invite; + + /** + * A list of objects representing third-party IDs to invite into + * the room. + * + * @var list<Invite3pid>|null $invite3pid + */ + #[Optional('invite_3pid', list: Invite3pid::class)] + public ?array $invite3pid; + + /** + * 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. + */ + #[Optional('is_direct')] + public ?bool $isDirect; + + /** + * 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`. + */ + #[Optional] + public ?string $name; + + /** + * 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. + */ + #[Optional('power_level_content_override')] + public mixed $powerLevelContentOverride; + + /** + * 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`. + * + * @var value-of<Preset>|null $preset + */ + #[Optional(enum: Preset::class)] + public ?string $preset; + + /** + * 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. + */ + #[Optional('room_alias_name')] + public ?string $roomAliasName; + + /** + * 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. + */ + #[Optional('room_version')] + public ?string $roomVersion; + + /** + * 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`. + */ + #[Optional] + public ?string $topic; + + /** + * 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`. + * + * @var value-of<Visibility>|null $visibility + */ + #[Optional(enum: Visibility::class)] + public ?string $visibility; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<InitialState|InitialStateShape>|null $initialState + * @param list<string>|null $invite + * @param list<Invite3pid|Invite3pidShape>|null $invite3pid + * @param Preset|value-of<Preset>|null $preset + * @param Visibility|value-of<Visibility>|null $visibility + */ + public static function with( + mixed $creationContent = null, + ?array $initialState = null, + ?array $invite = null, + ?array $invite3pid = null, + ?bool $isDirect = null, + ?string $name = null, + mixed $powerLevelContentOverride = null, + Preset|string|null $preset = null, + ?string $roomAliasName = null, + ?string $roomVersion = null, + ?string $topic = null, + Visibility|string|null $visibility = null, + ): self { + $self = new self; + + null !== $creationContent && $self['creationContent'] = $creationContent; + null !== $initialState && $self['initialState'] = $initialState; + null !== $invite && $self['invite'] = $invite; + null !== $invite3pid && $self['invite3pid'] = $invite3pid; + null !== $isDirect && $self['isDirect'] = $isDirect; + null !== $name && $self['name'] = $name; + null !== $powerLevelContentOverride && $self['powerLevelContentOverride'] = $powerLevelContentOverride; + null !== $preset && $self['preset'] = $preset; + null !== $roomAliasName && $self['roomAliasName'] = $roomAliasName; + null !== $roomVersion && $self['roomVersion'] = $roomVersion; + null !== $topic && $self['topic'] = $topic; + null !== $visibility && $self['visibility'] = $visibility; + + return $self; + } + + /** + * 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. + */ + public function withCreationContent(mixed $creationContent): self + { + $self = clone $this; + $self['creationContent'] = $creationContent; + + return $self; + } + + /** + * 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. + * + * @param list<InitialState|InitialStateShape> $initialState + */ + public function withInitialState(array $initialState): self + { + $self = clone $this; + $self['initialState'] = $initialState; + + return $self; + } + + /** + * 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. + * + * @param list<string> $invite + */ + public function withInvite(array $invite): self + { + $self = clone $this; + $self['invite'] = $invite; + + return $self; + } + + /** + * A list of objects representing third-party IDs to invite into + * the room. + * + * @param list<Invite3pid|Invite3pidShape> $invite3pid + */ + public function withInvite3pid(array $invite3pid): self + { + $self = clone $this; + $self['invite3pid'] = $invite3pid; + + return $self; + } + + /** + * 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. + */ + public function withIsDirect(bool $isDirect): self + { + $self = clone $this; + $self['isDirect'] = $isDirect; + + return $self; + } + + /** + * 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`. + */ + public function withName(string $name): self + { + $self = clone $this; + $self['name'] = $name; + + return $self; + } + + /** + * 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. + */ + public function withPowerLevelContentOverride( + mixed $powerLevelContentOverride + ): self { + $self = clone $this; + $self['powerLevelContentOverride'] = $powerLevelContentOverride; + + return $self; + } + + /** + * 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`. + * + * @param Preset|value-of<Preset> $preset + */ + public function withPreset(Preset|string $preset): self + { + $self = clone $this; + $self['preset'] = $preset; + + return $self; + } + + /** + * 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. + */ + public function withRoomAliasName(string $roomAliasName): self + { + $self = clone $this; + $self['roomAliasName'] = $roomAliasName; + + return $self; + } + + /** + * 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. + */ + public function withRoomVersion(string $roomVersion): self + { + $self = clone $this; + $self['roomVersion'] = $roomVersion; + + return $self; + } + + /** + * 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`. + */ + public function withTopic(string $topic): self + { + $self = clone $this; + $self['topic'] = $topic; + + return $self; + } + + /** + * 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`. + * + * @param Visibility|value-of<Visibility> $visibility + */ + public function withVisibility(Visibility|string $visibility): self + { + $self = clone $this; + $self['visibility'] = $visibility; + + return $self; + } +} diff --git a/src/Matrix/Rooms/RoomCreateParams/InitialState.php b/src/Matrix/Rooms/RoomCreateParams/InitialState.php new file mode 100644 index 0000000..a16eee8 --- /dev/null +++ b/src/Matrix/Rooms/RoomCreateParams/InitialState.php @@ -0,0 +1,111 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\RoomCreateParams; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-type InitialStateShape = array{ + * content: mixed, type: string, stateKey?: string|null + * } + */ +final class InitialState implements BaseModel +{ + /** @use SdkModel<InitialStateShape> */ + use SdkModel; + + /** + * The content of the event. + */ + #[Required] + public mixed $content; + + /** + * The type of event to send. + */ + #[Required] + public string $type; + + /** + * The state_key of the state event. Defaults to an empty string. + */ + #[Optional('state_key')] + public ?string $stateKey; + + /** + * `new InitialState()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * InitialState::with(content: ..., type: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new InitialState)->withContent(...)->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + mixed $content, + string $type, + ?string $stateKey = null + ): self { + $self = new self; + + $self['content'] = $content; + $self['type'] = $type; + + null !== $stateKey && $self['stateKey'] = $stateKey; + + return $self; + } + + /** + * The content of the event. + */ + public function withContent(mixed $content): self + { + $self = clone $this; + $self['content'] = $content; + + return $self; + } + + /** + * The type of event to send. + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * The state_key of the state event. Defaults to an empty string. + */ + public function withStateKey(string $stateKey): self + { + $self = clone $this; + $self['stateKey'] = $stateKey; + + return $self; + } +} diff --git a/src/Matrix/Rooms/RoomCreateParams/Invite3pid.php b/src/Matrix/Rooms/RoomCreateParams/Invite3pid.php new file mode 100644 index 0000000..4c9850c --- /dev/null +++ b/src/Matrix/Rooms/RoomCreateParams/Invite3pid.php @@ -0,0 +1,138 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\RoomCreateParams; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-type Invite3pidShape = array{ + * address: string, idAccessToken: string, idServer: string, medium: string + * } + */ +final class Invite3pid implements BaseModel +{ + /** @use SdkModel<Invite3pidShape> */ + use SdkModel; + + /** + * The invitee's third-party identifier. + */ + #[Required] + public string $address; + + /** + * 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. + */ + #[Required('id_access_token')] + public string $idAccessToken; + + /** + * The hostname+port of the identity server which should be used for third-party identifier lookups. + */ + #[Required('id_server')] + public string $idServer; + + /** + * 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)). + */ + #[Required] + public string $medium; + + /** + * `new Invite3pid()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * Invite3pid::with(address: ..., idAccessToken: ..., idServer: ..., medium: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new Invite3pid) + * ->withAddress(...) + * ->withIDAccessToken(...) + * ->withIDServer(...) + * ->withMedium(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + string $address, + string $idAccessToken, + string $idServer, + string $medium + ): self { + $self = new self; + + $self['address'] = $address; + $self['idAccessToken'] = $idAccessToken; + $self['idServer'] = $idServer; + $self['medium'] = $medium; + + return $self; + } + + /** + * The invitee's third-party identifier. + */ + public function withAddress(string $address): self + { + $self = clone $this; + $self['address'] = $address; + + return $self; + } + + /** + * 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. + */ + public function withIDAccessToken(string $idAccessToken): self + { + $self = clone $this; + $self['idAccessToken'] = $idAccessToken; + + return $self; + } + + /** + * The hostname+port of the identity server which should be used for third-party identifier lookups. + */ + public function withIDServer(string $idServer): self + { + $self = clone $this; + $self['idServer'] = $idServer; + + return $self; + } + + /** + * 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)). + */ + public function withMedium(string $medium): self + { + $self = clone $this; + $self['medium'] = $medium; + + return $self; + } +} diff --git a/src/Matrix/Rooms/RoomCreateParams/Preset.php b/src/Matrix/Rooms/RoomCreateParams/Preset.php new file mode 100644 index 0000000..64c5b49 --- /dev/null +++ b/src/Matrix/Rooms/RoomCreateParams/Preset.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\RoomCreateParams; + +/** + * 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`. + */ +enum Preset: string +{ + case PRIVATE_CHAT = 'private_chat'; + + case PUBLIC_CHAT = 'public_chat'; + + case TRUSTED_PRIVATE_CHAT = 'trusted_private_chat'; +} diff --git a/src/Matrix/Rooms/RoomCreateParams/Visibility.php b/src/Matrix/Rooms/RoomCreateParams/Visibility.php new file mode 100644 index 0000000..9b47751 --- /dev/null +++ b/src/Matrix/Rooms/RoomCreateParams/Visibility.php @@ -0,0 +1,17 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\RoomCreateParams; + +/** + * 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`. + */ +enum Visibility: string +{ + case PUBLIC = 'public'; + + case PRIVATE = 'private'; +} diff --git a/src/Matrix/Rooms/RoomJoinParams.php b/src/Matrix/Rooms/RoomJoinParams.php new file mode 100644 index 0000000..707a55c --- /dev/null +++ b/src/Matrix/Rooms/RoomJoinParams.php @@ -0,0 +1,131 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Rooms\RoomJoinParams\ThirdPartySigned; + +/** + * *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. + * + * @see BeeperDesktop\Services\Matrix\RoomsService::join() + * + * @phpstan-import-type ThirdPartySignedShape from \BeeperDesktop\Matrix\Rooms\RoomJoinParams\ThirdPartySigned + * + * @phpstan-type RoomJoinParamsShape = array{ + * via?: list<string>|null, + * reason?: string|null, + * thirdPartySigned?: null|ThirdPartySigned|ThirdPartySignedShape, + * } + */ +final class RoomJoinParams implements BaseModel +{ + /** @use SdkModel<RoomJoinParamsShape> */ + use SdkModel; + use SdkParams; + + /** + * The servers to attempt to join the room through. One of the servers + * must be participating in the room. + * + * @var list<string>|null $via + */ + #[Optional(list: 'string')] + public ?array $via; + + /** + * Optional reason to be included as the `reason` on the subsequent + * membership event. + */ + #[Optional] + public ?string $reason; + + /** + * 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. + */ + #[Optional('third_party_signed')] + public ?ThirdPartySigned $thirdPartySigned; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param list<string>|null $via + * @param ThirdPartySigned|ThirdPartySignedShape|null $thirdPartySigned + */ + public static function with( + ?array $via = null, + ?string $reason = null, + ThirdPartySigned|array|null $thirdPartySigned = null, + ): self { + $self = new self; + + null !== $via && $self['via'] = $via; + null !== $reason && $self['reason'] = $reason; + null !== $thirdPartySigned && $self['thirdPartySigned'] = $thirdPartySigned; + + return $self; + } + + /** + * The servers to attempt to join the room through. One of the servers + * must be participating in the room. + * + * @param list<string> $via + */ + public function withVia(array $via): self + { + $self = clone $this; + $self['via'] = $via; + + return $self; + } + + /** + * Optional reason to be included as the `reason` on the subsequent + * membership event. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } + + /** + * 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. + * + * @param ThirdPartySigned|ThirdPartySignedShape $thirdPartySigned + */ + public function withThirdPartySigned( + ThirdPartySigned|array $thirdPartySigned + ): self { + $self = clone $this; + $self['thirdPartySigned'] = $thirdPartySigned; + + return $self; + } +} diff --git a/src/Matrix/Rooms/RoomJoinParams/ThirdPartySigned.php b/src/Matrix/Rooms/RoomJoinParams/ThirdPartySigned.php new file mode 100644 index 0000000..556eb33 --- /dev/null +++ b/src/Matrix/Rooms/RoomJoinParams/ThirdPartySigned.php @@ -0,0 +1,145 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\RoomJoinParams; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Core\Conversion\MapOf; + +/** + * 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. + * + * @phpstan-type ThirdPartySignedShape = array{ + * token: string, + * mxid: string, + * sender: string, + * signatures: array<string,array<string,string>>, + * } + */ +final class ThirdPartySigned implements BaseModel +{ + /** @use SdkModel<ThirdPartySignedShape> */ + use SdkModel; + + /** + * The state key of the m.third_party_invite event. + */ + #[Required] + public string $token; + + /** + * The Matrix ID of the invitee. + */ + #[Required] + public string $mxid; + + /** + * The Matrix ID of the user who issued the invite. + */ + #[Required] + public string $sender; + + /** + * A signatures object containing a signature of the entire signed object. + * + * @var array<string,array<string,string>> $signatures + */ + #[Required(map: new MapOf('string'))] + public array $signatures; + + /** + * `new ThirdPartySigned()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * ThirdPartySigned::with(token: ..., mxid: ..., sender: ..., signatures: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new ThirdPartySigned) + * ->withToken(...) + * ->withMxid(...) + * ->withSender(...) + * ->withSignatures(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param array<string,array<string,string>> $signatures + */ + public static function with( + string $token, + string $mxid, + string $sender, + array $signatures + ): self { + $self = new self; + + $self['token'] = $token; + $self['mxid'] = $mxid; + $self['sender'] = $sender; + $self['signatures'] = $signatures; + + return $self; + } + + /** + * The state key of the m.third_party_invite event. + */ + public function withToken(string $token): self + { + $self = clone $this; + $self['token'] = $token; + + return $self; + } + + /** + * The Matrix ID of the invitee. + */ + public function withMxid(string $mxid): self + { + $self = clone $this; + $self['mxid'] = $mxid; + + return $self; + } + + /** + * The Matrix ID of the user who issued the invite. + */ + public function withSender(string $sender): self + { + $self = clone $this; + $self['sender'] = $sender; + + return $self; + } + + /** + * A signatures object containing a signature of the entire signed object. + * + * @param array<string,array<string,string>> $signatures + */ + public function withSignatures(array $signatures): self + { + $self = clone $this; + $self['signatures'] = $signatures; + + return $self; + } +} diff --git a/src/Matrix/Rooms/RoomJoinResponse.php b/src/Matrix/Rooms/RoomJoinResponse.php new file mode 100644 index 0000000..e03150b --- /dev/null +++ b/src/Matrix/Rooms/RoomJoinResponse.php @@ -0,0 +1,68 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-type RoomJoinResponseShape = array{roomID: string} + */ +final class RoomJoinResponse implements BaseModel +{ + /** @use SdkModel<RoomJoinResponseShape> */ + use SdkModel; + + /** + * The joined room ID. + */ + #[Required('room_id')] + public string $roomID; + + /** + * `new RoomJoinResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RoomJoinResponse::with(roomID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RoomJoinResponse)->withRoomID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $roomID): self + { + $self = new self; + + $self['roomID'] = $roomID; + + return $self; + } + + /** + * The joined room ID. + */ + public function withRoomID(string $roomID): self + { + $self = clone $this; + $self['roomID'] = $roomID; + + return $self; + } +} diff --git a/src/Matrix/Rooms/RoomLeaveParams.php b/src/Matrix/Rooms/RoomLeaveParams.php new file mode 100644 index 0000000..10bd611 --- /dev/null +++ b/src/Matrix/Rooms/RoomLeaveParams.php @@ -0,0 +1,79 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * 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. + * + * @see BeeperDesktop\Services\Matrix\RoomsService::leave() + * + * @phpstan-type RoomLeaveParamsShape = array{reason?: string|null} + */ +final class RoomLeaveParams implements BaseModel +{ + /** @use SdkModel<RoomLeaveParamsShape> */ + use SdkModel; + use SdkParams; + + /** + * Optional reason to be included as the `reason` on the subsequent + * membership event. + */ + #[Optional] + public ?string $reason; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(?string $reason = null): self + { + $self = new self; + + null !== $reason && $self['reason'] = $reason; + + return $self; + } + + /** + * Optional reason to be included as the `reason` on the subsequent + * membership event. + */ + public function withReason(string $reason): self + { + $self = clone $this; + $self['reason'] = $reason; + + return $self; + } +} diff --git a/src/Matrix/Rooms/RoomNewResponse.php b/src/Matrix/Rooms/RoomNewResponse.php new file mode 100644 index 0000000..a000e74 --- /dev/null +++ b/src/Matrix/Rooms/RoomNewResponse.php @@ -0,0 +1,70 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Information about the newly created room. + * + * @phpstan-type RoomNewResponseShape = array{roomID: string} + */ +final class RoomNewResponse implements BaseModel +{ + /** @use SdkModel<RoomNewResponseShape> */ + use SdkModel; + + /** + * The created room's ID. + */ + #[Required('room_id')] + public string $roomID; + + /** + * `new RoomNewResponse()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * RoomNewResponse::with(roomID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new RoomNewResponse)->withRoomID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $roomID): self + { + $self = new self; + + $self['roomID'] = $roomID; + + return $self; + } + + /** + * The created room's ID. + */ + public function withRoomID(string $roomID): self + { + $self = clone $this; + $self['roomID'] = $roomID; + + return $self; + } +} diff --git a/src/Matrix/Rooms/State/StateListResponseItem.php b/src/Matrix/Rooms/State/StateListResponseItem.php new file mode 100644 index 0000000..0bc3e74 --- /dev/null +++ b/src/Matrix/Rooms/State/StateListResponseItem.php @@ -0,0 +1,245 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\State; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Rooms\State\StateListResponseItem\Unsigned; + +/** + * 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. + * + * @phpstan-import-type UnsignedShape from \BeeperDesktop\Matrix\Rooms\State\StateListResponseItem\Unsigned + * + * @phpstan-type StateListResponseItemShape = array{ + * content: mixed, + * eventID: string, + * originServerTs: int, + * roomID: string, + * sender: string, + * type: string, + * stateKey?: string|null, + * unsigned?: null|Unsigned|UnsignedShape, + * } + */ +final class StateListResponseItem implements BaseModel +{ + /** @use SdkModel<StateListResponseItemShape> */ + use SdkModel; + + /** + * The body of this event, as created by the client which sent it. + */ + #[Required] + public mixed $content; + + /** + * The globally unique identifier for this event. + */ + #[Required('event_id')] + public string $eventID; + + /** + * Timestamp (in milliseconds since the unix epoch) on originating homeserver + * when this event was sent. + */ + #[Required('origin_server_ts')] + public int $originServerTs; + + /** + * The ID of the room associated with this event. + */ + #[Required('room_id')] + public string $roomID; + + /** + * Contains the fully-qualified ID of the user who sent this event. + */ + #[Required] + public string $sender; + + /** + * The type of the event. + */ + #[Required] + public string $type; + + /** + * 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. + */ + #[Optional('state_key')] + public ?string $stateKey; + + #[Optional] + public ?Unsigned $unsigned; + + /** + * `new StateListResponseItem()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * StateListResponseItem::with( + * content: ..., + * eventID: ..., + * originServerTs: ..., + * roomID: ..., + * sender: ..., + * type: ..., + * ) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new StateListResponseItem) + * ->withContent(...) + * ->withEventID(...) + * ->withOriginServerTs(...) + * ->withRoomID(...) + * ->withSender(...) + * ->withType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Unsigned|UnsignedShape|null $unsigned + */ + public static function with( + mixed $content, + string $eventID, + int $originServerTs, + string $roomID, + string $sender, + string $type, + ?string $stateKey = null, + Unsigned|array|null $unsigned = null, + ): self { + $self = new self; + + $self['content'] = $content; + $self['eventID'] = $eventID; + $self['originServerTs'] = $originServerTs; + $self['roomID'] = $roomID; + $self['sender'] = $sender; + $self['type'] = $type; + + null !== $stateKey && $self['stateKey'] = $stateKey; + null !== $unsigned && $self['unsigned'] = $unsigned; + + return $self; + } + + /** + * The body of this event, as created by the client which sent it. + */ + public function withContent(mixed $content): self + { + $self = clone $this; + $self['content'] = $content; + + return $self; + } + + /** + * The globally unique identifier for this event. + */ + public function withEventID(string $eventID): self + { + $self = clone $this; + $self['eventID'] = $eventID; + + return $self; + } + + /** + * Timestamp (in milliseconds since the unix epoch) on originating homeserver + * when this event was sent. + */ + public function withOriginServerTs(int $originServerTs): self + { + $self = clone $this; + $self['originServerTs'] = $originServerTs; + + return $self; + } + + /** + * The ID of the room associated with this event. + */ + public function withRoomID(string $roomID): self + { + $self = clone $this; + $self['roomID'] = $roomID; + + return $self; + } + + /** + * Contains the fully-qualified ID of the user who sent this event. + */ + public function withSender(string $sender): self + { + $self = clone $this; + $self['sender'] = $sender; + + return $self; + } + + /** + * The type of the event. + */ + public function withType(string $type): self + { + $self = clone $this; + $self['type'] = $type; + + return $self; + } + + /** + * 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. + */ + public function withStateKey(string $stateKey): self + { + $self = clone $this; + $self['stateKey'] = $stateKey; + + return $self; + } + + /** + * @param Unsigned|UnsignedShape $unsigned + */ + public function withUnsigned(Unsigned|array $unsigned): self + { + $self = clone $this; + $self['unsigned'] = $unsigned; + + return $self; + } +} diff --git a/src/Matrix/Rooms/State/StateListResponseItem/Unsigned.php b/src/Matrix/Rooms/State/StateListResponseItem/Unsigned.php new file mode 100644 index 0000000..0d87337 --- /dev/null +++ b/src/Matrix/Rooms/State/StateListResponseItem/Unsigned.php @@ -0,0 +1,167 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\State\StateListResponseItem; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-type UnsignedShape = array{ + * age?: int|null, + * membership?: string|null, + * prevContent?: mixed, + * redactedBecause?: mixed, + * transactionID?: string|null, + * } + */ +final class Unsigned implements BaseModel +{ + /** @use SdkModel<UnsignedShape> */ + use SdkModel; + + /** + * 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. + */ + #[Optional] + public ?int $age; + + /** + * 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"). + */ + #[Optional] + public ?string $membership; + + /** + * 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. + */ + #[Optional('prev_content')] + public mixed $prevContent; + + #[Optional('redacted_because')] + public mixed $redactedBecause; + + /** + * 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. + */ + #[Optional('transaction_id')] + public ?string $transactionID; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?int $age = null, + ?string $membership = null, + mixed $prevContent = null, + mixed $redactedBecause = null, + ?string $transactionID = null, + ): self { + $self = new self; + + null !== $age && $self['age'] = $age; + null !== $membership && $self['membership'] = $membership; + null !== $prevContent && $self['prevContent'] = $prevContent; + null !== $redactedBecause && $self['redactedBecause'] = $redactedBecause; + null !== $transactionID && $self['transactionID'] = $transactionID; + + return $self; + } + + /** + * 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. + */ + public function withAge(int $age): self + { + $self = clone $this; + $self['age'] = $age; + + return $self; + } + + /** + * 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"). + */ + public function withMembership(string $membership): self + { + $self = clone $this; + $self['membership'] = $membership; + + return $self; + } + + /** + * 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. + */ + public function withPrevContent(mixed $prevContent): self + { + $self = clone $this; + $self['prevContent'] = $prevContent; + + return $self; + } + + public function withRedactedBecause(mixed $redactedBecause): self + { + $self = clone $this; + $self['redactedBecause'] = $redactedBecause; + + return $self; + } + + /** + * 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. + */ + public function withTransactionID(string $transactionID): self + { + $self = clone $this; + $self['transactionID'] = $transactionID; + + return $self; + } +} diff --git a/src/Matrix/Rooms/State/StateRetrieveParams.php b/src/Matrix/Rooms/State/StateRetrieveParams.php new file mode 100644 index 0000000..86e470b --- /dev/null +++ b/src/Matrix/Rooms/State/StateRetrieveParams.php @@ -0,0 +1,121 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\State; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; +use BeeperDesktop\Matrix\Rooms\State\StateRetrieveParams\Format; + +/** + * 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. + * + * @see BeeperDesktop\Services\Matrix\Rooms\StateService::retrieve() + * + * @phpstan-type StateRetrieveParamsShape = array{ + * roomID: string, eventType: string, format?: null|Format|value-of<Format> + * } + */ +final class StateRetrieveParams implements BaseModel +{ + /** @use SdkModel<StateRetrieveParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $roomID; + + #[Required] + public string $eventType; + + /** + * 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. + * + * @var value-of<Format>|null $format + */ + #[Optional(enum: Format::class)] + public ?string $format; + + /** + * `new StateRetrieveParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * StateRetrieveParams::with(roomID: ..., eventType: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new StateRetrieveParams)->withRoomID(...)->withEventType(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + * + * @param Format|value-of<Format>|null $format + */ + public static function with( + string $roomID, + string $eventType, + Format|string|null $format = null + ): self { + $self = new self; + + $self['roomID'] = $roomID; + $self['eventType'] = $eventType; + + null !== $format && $self['format'] = $format; + + return $self; + } + + public function withRoomID(string $roomID): self + { + $self = clone $this; + $self['roomID'] = $roomID; + + return $self; + } + + public function withEventType(string $eventType): self + { + $self = clone $this; + $self['eventType'] = $eventType; + + return $self; + } + + /** + * 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. + * + * @param Format|value-of<Format> $format + */ + public function withFormat(Format|string $format): self + { + $self = clone $this; + $self['format'] = $format; + + return $self; + } +} diff --git a/src/Matrix/Rooms/State/StateRetrieveParams/Format.php b/src/Matrix/Rooms/State/StateRetrieveParams/Format.php new file mode 100644 index 0000000..7b3f074 --- /dev/null +++ b/src/Matrix/Rooms/State/StateRetrieveParams/Format.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Rooms\State\StateRetrieveParams; + +/** + * 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. + */ +enum Format: string +{ + case CONTENT = 'content'; + + case EVENT = 'event'; +} diff --git a/src/Matrix/Users/AccountData/AccountDataRetrieveParams.php b/src/Matrix/Users/AccountData/AccountDataRetrieveParams.php new file mode 100644 index 0000000..681d3c5 --- /dev/null +++ b/src/Matrix/Users/AccountData/AccountDataRetrieveParams.php @@ -0,0 +1,69 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Users\AccountData; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * Get some account data for the client. This config is only visible to the user + * that set the account data. + * + * @see BeeperDesktop\Services\Matrix\Users\AccountDataService::retrieve() + * + * @phpstan-type AccountDataRetrieveParamsShape = array{userID: string} + */ +final class AccountDataRetrieveParams implements BaseModel +{ + /** @use SdkModel<AccountDataRetrieveParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $userID; + + /** + * `new AccountDataRetrieveParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AccountDataRetrieveParams::with(userID: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AccountDataRetrieveParams)->withUserID(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $userID): self + { + $self = new self; + + $self['userID'] = $userID; + + return $self; + } + + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } +} diff --git a/src/Matrix/Users/AccountData/AccountDataUpdateParams.php b/src/Matrix/Users/AccountData/AccountDataUpdateParams.php new file mode 100644 index 0000000..4b7db84 --- /dev/null +++ b/src/Matrix/Users/AccountData/AccountDataUpdateParams.php @@ -0,0 +1,83 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Users\AccountData; + +use BeeperDesktop\Core\Attributes\Required; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Concerns\SdkParams; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * 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). + * + * @see BeeperDesktop\Services\Matrix\Users\AccountDataService::update() + * + * @phpstan-type AccountDataUpdateParamsShape = array{userID: string, body: mixed} + */ +final class AccountDataUpdateParams implements BaseModel +{ + /** @use SdkModel<AccountDataUpdateParamsShape> */ + use SdkModel; + use SdkParams; + + #[Required] + public string $userID; + + #[Required] + public mixed $body; + + /** + * `new AccountDataUpdateParams()` is missing required properties by the API. + * + * To enforce required parameters use + * ``` + * AccountDataUpdateParams::with(userID: ..., body: ...) + * ``` + * + * Otherwise ensure the following setters are called + * + * ``` + * (new AccountDataUpdateParams)->withUserID(...)->withBody(...) + * ``` + */ + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with(string $userID, mixed $body): self + { + $self = new self; + + $self['userID'] = $userID; + $self['body'] = $body; + + return $self; + } + + public function withUserID(string $userID): self + { + $self = clone $this; + $self['userID'] = $userID; + + return $self; + } + + public function withBody(mixed $body): self + { + $self = clone $this; + $self['body'] = $body; + + return $self; + } +} diff --git a/src/Matrix/Users/UserGetProfileResponse.php b/src/Matrix/Users/UserGetProfileResponse.php new file mode 100644 index 0000000..76fbfa0 --- /dev/null +++ b/src/Matrix/Users/UserGetProfileResponse.php @@ -0,0 +1,95 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Matrix\Users; + +use BeeperDesktop\Core\Attributes\Optional; +use BeeperDesktop\Core\Concerns\SdkModel; +use BeeperDesktop\Core\Contracts\BaseModel; + +/** + * @phpstan-type UserGetProfileResponseShape = array{ + * avatarURL?: string|null, displayname?: string|null, mTz?: string|null + * } + */ +final class UserGetProfileResponse implements BaseModel +{ + /** @use SdkModel<UserGetProfileResponseShape> */ + use SdkModel; + + /** + * The user's avatar URL if they have set one, otherwise not present. + */ + #[Optional('avatar_url')] + public ?string $avatarURL; + + /** + * The user's display name if they have set one, otherwise not present. + */ + #[Optional] + public ?string $displayname; + + /** + * The user's time zone. + */ + #[Optional('m.tz')] + public ?string $mTz; + + public function __construct() + { + $this->initialize(); + } + + /** + * Construct an instance from the required parameters. + * + * You must use named parameters to construct any parameters with a default value. + */ + public static function with( + ?string $avatarURL = null, + ?string $displayname = null, + ?string $mTz = null + ): self { + $self = new self; + + null !== $avatarURL && $self['avatarURL'] = $avatarURL; + null !== $displayname && $self['displayname'] = $displayname; + null !== $mTz && $self['mTz'] = $mTz; + + return $self; + } + + /** + * The user's avatar URL if they have set one, otherwise not present. + */ + public function withAvatarURL(string $avatarURL): self + { + $self = clone $this; + $self['avatarURL'] = $avatarURL; + + return $self; + } + + /** + * The user's display name if they have set one, otherwise not present. + */ + public function withDisplayname(string $displayname): self + { + $self = clone $this; + $self['displayname'] = $displayname; + + return $self; + } + + /** + * The user's time zone. + */ + public function withMTz(string $mTz): self + { + $self = clone $this; + $self['mTz'] = $mTz; + + return $self; + } +} diff --git a/src/ServiceContracts/App/E2ee/RecoveryCode/ResetContract.php b/src/ServiceContracts/App/E2ee/RecoveryCode/ResetContract.php new file mode 100644 index 0000000..dd1d008 --- /dev/null +++ b/src/ServiceContracts/App/E2ee/RecoveryCode/ResetContract.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee\RecoveryCode; + +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetConfirmResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetNewResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface ResetContract +{ + /** + * @api + * + * @param string $recoveryCode existing recovery key, if the user has it + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function create( + ?string $recoveryCode = null, + RequestOptions|array|null $requestOptions = null, + ): ResetNewResponse; + + /** + * @api + * + * @param string $recoveryCode new recovery key returned by the reset step + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function confirm( + string $recoveryCode, + RequestOptions|array|null $requestOptions = null + ): ResetConfirmResponse; +} diff --git a/src/ServiceContracts/App/E2ee/RecoveryCode/ResetRawContract.php b/src/ServiceContracts/App/E2ee/RecoveryCode/ResetRawContract.php new file mode 100644 index 0000000..a800c9e --- /dev/null +++ b/src/ServiceContracts/App/E2ee/RecoveryCode/ResetRawContract.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee\RecoveryCode; + +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetConfirmParams; +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetConfirmResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetCreateParams; +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetNewResponse; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface ResetRawContract +{ + /** + * @api + * + * @param array<string,mixed>|ResetCreateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<ResetNewResponse> + * + * @throws APIException + */ + public function create( + array|ResetCreateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param array<string,mixed>|ResetConfirmParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<ResetConfirmResponse> + * + * @throws APIException + */ + public function confirm( + array|ResetConfirmParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/App/E2ee/RecoveryCodeContract.php b/src/ServiceContracts/App/E2ee/RecoveryCodeContract.php new file mode 100644 index 0000000..e5f5031 --- /dev/null +++ b/src/ServiceContracts/App/E2ee/RecoveryCodeContract.php @@ -0,0 +1,40 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee; + +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeMarkBackedUpResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeVerifyResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface RecoveryCodeContract +{ + /** + * @api + * + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function markBackedUp( + RequestOptions|array|null $requestOptions = null + ): RecoveryCodeMarkBackedUpResponse; + + /** + * @api + * + * @param string $recoveryCode recovery key saved by the user + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function verify( + string $recoveryCode, + RequestOptions|array|null $requestOptions = null + ): RecoveryCodeVerifyResponse; +} diff --git a/src/ServiceContracts/App/E2ee/RecoveryCodeRawContract.php b/src/ServiceContracts/App/E2ee/RecoveryCodeRawContract.php new file mode 100644 index 0000000..2d80bf4 --- /dev/null +++ b/src/ServiceContracts/App/E2ee/RecoveryCodeRawContract.php @@ -0,0 +1,46 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee; + +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeMarkBackedUpResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeVerifyParams; +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeVerifyResponse; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface RecoveryCodeRawContract +{ + /** + * @api + * + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RecoveryCodeMarkBackedUpResponse> + * + * @throws APIException + */ + public function markBackedUp( + RequestOptions|array|null $requestOptions = null + ): BaseResponse; + + /** + * @api + * + * @param array<string,mixed>|RecoveryCodeVerifyParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RecoveryCodeVerifyResponse> + * + * @throws APIException + */ + public function verify( + array|RecoveryCodeVerifyParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/App/E2ee/Verification/QrContract.php b/src/ServiceContracts/App/E2ee/Verification/QrContract.php new file mode 100644 index 0000000..998b996 --- /dev/null +++ b/src/ServiceContracts/App/E2ee/Verification/QrContract.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Qr\QrConfirmScannedResponse; +use BeeperDesktop\App\E2ee\Verification\Qr\QrScanResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface QrContract +{ + /** + * @api + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function confirmScanned( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): QrConfirmScannedResponse; + + /** + * @api + * + * @param string $data QR code payload scanned from the other device + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function scan( + string $data, + RequestOptions|array|null $requestOptions = null + ): QrScanResponse; +} diff --git a/src/ServiceContracts/App/E2ee/Verification/QrRawContract.php b/src/ServiceContracts/App/E2ee/Verification/QrRawContract.php new file mode 100644 index 0000000..04c00dd --- /dev/null +++ b/src/ServiceContracts/App/E2ee/Verification/QrRawContract.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Qr\QrConfirmScannedResponse; +use BeeperDesktop\App\E2ee\Verification\Qr\QrScanParams; +use BeeperDesktop\App\E2ee\Verification\Qr\QrScanResponse; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface QrRawContract +{ + /** + * @api + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<QrConfirmScannedResponse> + * + * @throws APIException + */ + public function confirmScanned( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; + + /** + * @api + * + * @param array<string,mixed>|QrScanParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<QrScanResponse> + * + * @throws APIException + */ + public function scan( + array|QrScanParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/App/E2ee/Verification/SasContract.php b/src/ServiceContracts/App/E2ee/Verification/SasContract.php new file mode 100644 index 0000000..4921bae --- /dev/null +++ b/src/ServiceContracts/App/E2ee/Verification/SasContract.php @@ -0,0 +1,42 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Sas\SaConfirmResponse; +use BeeperDesktop\App\E2ee\Verification\Sas\SaStartResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface SasContract +{ + /** + * @api + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function confirm( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): SaConfirmResponse; + + /** + * @api + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function start( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): SaStartResponse; +} diff --git a/src/ServiceContracts/App/E2ee/Verification/SasRawContract.php b/src/ServiceContracts/App/E2ee/Verification/SasRawContract.php new file mode 100644 index 0000000..07de35d --- /dev/null +++ b/src/ServiceContracts/App/E2ee/Verification/SasRawContract.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Sas\SaConfirmResponse; +use BeeperDesktop\App\E2ee\Verification\Sas\SaStartResponse; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface SasRawContract +{ + /** + * @api + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<SaConfirmResponse> + * + * @throws APIException + */ + public function confirm( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; + + /** + * @api + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<SaStartResponse> + * + * @throws APIException + */ + public function start( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; +} diff --git a/src/ServiceContracts/App/E2ee/VerificationContract.php b/src/ServiceContracts/App/E2ee/VerificationContract.php new file mode 100644 index 0000000..6b9e33c --- /dev/null +++ b/src/ServiceContracts/App/E2ee/VerificationContract.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee; + +use BeeperDesktop\App\E2ee\Verification\VerificationAcceptResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationCancelResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationNewResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface VerificationContract +{ + /** + * @api + * + * @param string $userID User ID to verify. Defaults to the signed-in user. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function create( + ?string $userID = null, + RequestOptions|array|null $requestOptions = null + ): VerificationNewResponse; + + /** + * @api + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function accept( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): VerificationAcceptResponse; + + /** + * @api + * + * @param string $verificationID verification ID + * @param string $code optional cancellation code + * @param string $reason optional user-facing cancellation reason + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function cancel( + string $verificationID, + ?string $code = null, + ?string $reason = null, + RequestOptions|array|null $requestOptions = null, + ): VerificationCancelResponse; +} diff --git a/src/ServiceContracts/App/E2ee/VerificationRawContract.php b/src/ServiceContracts/App/E2ee/VerificationRawContract.php new file mode 100644 index 0000000..1dea9bb --- /dev/null +++ b/src/ServiceContracts/App/E2ee/VerificationRawContract.php @@ -0,0 +1,67 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App\E2ee; + +use BeeperDesktop\App\E2ee\Verification\VerificationAcceptResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationCancelParams; +use BeeperDesktop\App\E2ee\Verification\VerificationCancelResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationCreateParams; +use BeeperDesktop\App\E2ee\Verification\VerificationNewResponse; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface VerificationRawContract +{ + /** + * @api + * + * @param array<string,mixed>|VerificationCreateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<VerificationNewResponse> + * + * @throws APIException + */ + public function create( + array|VerificationCreateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<VerificationAcceptResponse> + * + * @throws APIException + */ + public function accept( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; + + /** + * @api + * + * @param string $verificationID verification ID + * @param array<string,mixed>|VerificationCancelParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<VerificationCancelResponse> + * + * @throws APIException + */ + public function cancel( + string $verificationID, + array|VerificationCancelParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/App/E2eeContract.php b/src/ServiceContracts/App/E2eeContract.php new file mode 100644 index 0000000..c387d81 --- /dev/null +++ b/src/ServiceContracts/App/E2eeContract.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App; + +interface E2eeContract {} diff --git a/src/ServiceContracts/App/E2eeRawContract.php b/src/ServiceContracts/App/E2eeRawContract.php new file mode 100644 index 0000000..f98d742 --- /dev/null +++ b/src/ServiceContracts/App/E2eeRawContract.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App; + +interface E2eeRawContract {} diff --git a/src/ServiceContracts/App/LoginContract.php b/src/ServiceContracts/App/LoginContract.php new file mode 100644 index 0000000..f0b3d50 --- /dev/null +++ b/src/ServiceContracts/App/LoginContract.php @@ -0,0 +1,78 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App; + +use BeeperDesktop\App\Login\LoginRegisterResponse; +use BeeperDesktop\App\Login\LoginResponseResponse\UnionMember0; +use BeeperDesktop\App\Login\LoginResponseResponse\UnionMember1; +use BeeperDesktop\App\Login\LoginStartResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface LoginContract +{ + /** + * @api + * + * @param string $email email address to send the sign-in code to + * @param string $request login request ID returned by the start step + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function email( + string $email, + string $request, + RequestOptions|array|null $requestOptions = null, + ): mixed; + + /** + * @api + * + * @param bool $acceptTerms confirms that the user accepted the Terms of Use and acknowledged the Privacy Policy + * @param string $leadToken registration token returned by Beeper + * @param string $request login request ID returned by the start step + * @param string $username username selected by the user + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function register( + bool $acceptTerms, + string $leadToken, + string $request, + string $username, + RequestOptions|array|null $requestOptions = null, + ): LoginRegisterResponse; + + /** + * @api + * + * @param string $request login request ID returned by the start step + * @param string $response sign-in code from the user email + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function response( + string $request, + string $response, + RequestOptions|array|null $requestOptions = null, + ): UnionMember0|UnionMember1; + + /** + * @api + * + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function start( + RequestOptions|array|null $requestOptions = null + ): LoginStartResponse; +} diff --git a/src/ServiceContracts/App/LoginRawContract.php b/src/ServiceContracts/App/LoginRawContract.php new file mode 100644 index 0000000..4492a1c --- /dev/null +++ b/src/ServiceContracts/App/LoginRawContract.php @@ -0,0 +1,80 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\App; + +use BeeperDesktop\App\Login\LoginEmailParams; +use BeeperDesktop\App\Login\LoginRegisterParams; +use BeeperDesktop\App\Login\LoginRegisterResponse; +use BeeperDesktop\App\Login\LoginResponseParams; +use BeeperDesktop\App\Login\LoginResponseResponse\UnionMember0; +use BeeperDesktop\App\Login\LoginResponseResponse\UnionMember1; +use BeeperDesktop\App\Login\LoginStartResponse; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface LoginRawContract +{ + /** + * @api + * + * @param array<string,mixed>|LoginEmailParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function email( + array|LoginEmailParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param array<string,mixed>|LoginRegisterParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<LoginRegisterResponse> + * + * @throws APIException + */ + public function register( + array|LoginRegisterParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param array<string,mixed>|LoginResponseParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UnionMember0|UnionMember1> + * + * @throws APIException + */ + public function response( + array|LoginResponseParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<LoginStartResponse> + * + * @throws APIException + */ + public function start( + RequestOptions|array|null $requestOptions = null + ): BaseResponse; +} diff --git a/src/ServiceContracts/AppContract.php b/src/ServiceContracts/AppContract.php new file mode 100644 index 0000000..b968dce --- /dev/null +++ b/src/ServiceContracts/AppContract.php @@ -0,0 +1,26 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts; + +use BeeperDesktop\App\AppStatusResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface AppContract +{ + /** + * @api + * + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function status( + RequestOptions|array|null $requestOptions = null + ): AppStatusResponse; +} diff --git a/src/ServiceContracts/AppRawContract.php b/src/ServiceContracts/AppRawContract.php new file mode 100644 index 0000000..2721e66 --- /dev/null +++ b/src/ServiceContracts/AppRawContract.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts; + +use BeeperDesktop\App\AppStatusResponse; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface AppRawContract +{ + /** + * @api + * + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AppStatusResponse> + * + * @throws APIException + */ + public function status( + RequestOptions|array|null $requestOptions = null + ): BaseResponse; +} diff --git a/src/ServiceContracts/BridgesContract.php b/src/ServiceContracts/BridgesContract.php new file mode 100644 index 0000000..0f146a3 --- /dev/null +++ b/src/ServiceContracts/BridgesContract.php @@ -0,0 +1,26 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts; + +use BeeperDesktop\Bridges\BridgeListResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface BridgesContract +{ + /** + * @api + * + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function list( + RequestOptions|array|null $requestOptions = null + ): BridgeListResponse; +} diff --git a/src/ServiceContracts/BridgesRawContract.php b/src/ServiceContracts/BridgesRawContract.php new file mode 100644 index 0000000..524b8df --- /dev/null +++ b/src/ServiceContracts/BridgesRawContract.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts; + +use BeeperDesktop\Bridges\BridgeListResponse; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface BridgesRawContract +{ + /** + * @api + * + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<BridgeListResponse> + * + * @throws APIException + */ + public function list( + RequestOptions|array|null $requestOptions = null + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/Bridges/AuthContract.php b/src/ServiceContracts/Matrix/Bridges/AuthContract.php new file mode 100644 index 0000000..3d3b8aa --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/AuthContract.php @@ -0,0 +1,147 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListFlowsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListLoginsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember3; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface AuthContract +{ + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function listFlows( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): AuthListFlowsResponse; + + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function listLogins( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): AuthListLoginsResponse; + + /** + * @api + * + * @param string $loginID The unique ID of a login. Defined by the network connector. + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function logout( + string $loginID, + string $bridgeID, + RequestOptions|array|null $requestOptions = null, + ): mixed; + + /** + * @api + * + * @param string $flowID path param: The login flow ID to use + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID Query param: 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. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function startLogin( + string $flowID, + string $bridgeID, + ?string $loginID = null, + RequestOptions|array|null $requestOptions = null, + ): UnionMember0|UnionMember1|UnionMember2|UnionMember3; + + /** + * @api + * + * @param string $stepID path param: The ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginProcessID path param: The ID of the login process, as returned in the `login_id` field of the start call + * @param array<string,string> $body Body param + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function submitCookies( + string $stepID, + string $bridgeID, + string $loginProcessID, + array $body, + RequestOptions|array|null $requestOptions = null, + ): \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember3; + + /** + * @api + * + * @param string $stepID path param: The ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginProcessID path param: The ID of the login process, as returned in the `login_id` field of the start call + * @param array<string,string> $body Body param + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function submitUserInput( + string $stepID, + string $bridgeID, + string $loginProcessID, + array $body, + RequestOptions|array|null $requestOptions = null, + ): \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember3; + + /** + * @api + * + * @param string $stepID the ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginProcessID the ID of the login process, as returned in the `login_id` field of the start call + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function waitForStep( + string $stepID, + string $bridgeID, + string $loginProcessID, + RequestOptions|array|null $requestOptions = null, + ): \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0|\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1|\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2|\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember3; + + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function whoami( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): AuthWhoamiResponse; +} diff --git a/src/ServiceContracts/Matrix/Bridges/AuthRawContract.php b/src/ServiceContracts/Matrix/Bridges/AuthRawContract.php new file mode 100644 index 0000000..405daeb --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/AuthRawContract.php @@ -0,0 +1,157 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListFlowsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListLoginsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthLogoutParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember3; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface AuthRawContract +{ + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AuthListFlowsResponse> + * + * @throws APIException + */ + public function listFlows( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; + + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AuthListLoginsResponse> + * + * @throws APIException + */ + public function listLogins( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; + + /** + * @api + * + * @param string $loginID The unique ID of a login. Defined by the network connector. + * @param array<string,mixed>|AuthLogoutParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function logout( + string $loginID, + array|AuthLogoutParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $flowID path param: The login flow ID to use + * @param array<string,mixed>|AuthStartLoginParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UnionMember0|UnionMember1|UnionMember2|UnionMember3> + * + * @throws APIException + */ + public function startLogin( + string $flowID, + array|AuthStartLoginParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $stepID path param: The ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param array<string,mixed>|AuthSubmitCookiesParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember3,> + * + * @throws APIException + */ + public function submitCookies( + string $stepID, + array|AuthSubmitCookiesParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $stepID path param: The ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param array<string,mixed>|AuthSubmitUserInputParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember3,> + * + * @throws APIException + */ + public function submitUserInput( + string $stepID, + array|AuthSubmitUserInputParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $stepID the ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param array<string,mixed>|AuthWaitForStepParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0|\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1|\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2|\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember3,> + * + * @throws APIException + */ + public function waitForStep( + string $stepID, + array|AuthWaitForStepParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AuthWhoamiResponse> + * + * @throws APIException + */ + public function whoami( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/Bridges/CapabilitiesContract.php b/src/ServiceContracts/Matrix/Bridges/CapabilitiesContract.php new file mode 100644 index 0000000..dc4c669 --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/CapabilitiesContract.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface CapabilitiesContract +{ + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return array<string,mixed> + * + * @throws APIException + */ + public function retrieve( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): array; +} diff --git a/src/ServiceContracts/Matrix/Bridges/CapabilitiesRawContract.php b/src/ServiceContracts/Matrix/Bridges/CapabilitiesRawContract.php new file mode 100644 index 0000000..f69295d --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/CapabilitiesRawContract.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface CapabilitiesRawContract +{ + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<array<string,mixed>> + * + * @throws APIException + */ + public function retrieve( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/Bridges/ContactsContract.php b/src/ServiceContracts/Matrix/Bridges/ContactsContract.php new file mode 100644 index 0000000..7ea71e4 --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/ContactsContract.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Bridges\Contacts\ContactListResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface ContactsContract +{ + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID an optional explicit login ID to do the action through + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function list( + string $bridgeID, + ?string $loginID = null, + RequestOptions|array|null $requestOptions = null, + ): ContactListResponse; +} diff --git a/src/ServiceContracts/Matrix/Bridges/ContactsRawContract.php b/src/ServiceContracts/Matrix/Bridges/ContactsRawContract.php new file mode 100644 index 0000000..c8c1ddf --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/ContactsRawContract.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Bridges\Contacts\ContactListParams; +use BeeperDesktop\Matrix\Bridges\Contacts\ContactListResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface ContactsRawContract +{ + /** + * @api + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param array<string,mixed>|ContactListParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<ContactListResponse> + * + * @throws APIException + */ + public function list( + string $bridgeID, + array|ContactListParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/Bridges/RoomsContract.php b/src/ServiceContracts/Matrix/Bridges/RoomsContract.php new file mode 100644 index 0000000..07d6ff7 --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/RoomsContract.php @@ -0,0 +1,77 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Avatar; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Disappear; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Name; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Topic; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewDmResponse; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewGroupResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type AvatarShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Avatar + * @phpstan-import-type DisappearShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Disappear + * @phpstan-import-type NameShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Name + * @phpstan-import-type TopicShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Topic + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface RoomsContract +{ + /** + * @api + * + * @param string $identifier path param: The identifier to resolve or start a chat with + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID query param: An optional explicit login ID to do the action through + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function createDm( + string $identifier, + string $bridgeID, + ?string $loginID = null, + RequestOptions|array|null $requestOptions = null, + ): RoomNewDmResponse; + + /** + * @api + * + * @param string $groupType path param: Group type to create + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID query param: An optional explicit login ID to do the action through + * @param Avatar|AvatarShape $avatar Body param: The `m.room.avatar` event content for the room. + * @param Disappear|DisappearShape $disappear Body param: The `com.beeper.disappearing_timer` event content for the room. + * @param Name|NameShape $name Body param: The `m.room.name` event content for the room. + * @param mixed $parent Body param + * @param list<string> $participants body param: The users to add to the group initially + * @param string $roomID Body param: An existing Matrix room ID to bridge to. + * The other parameters must be already in sync with the room state when using this parameter. + * @param Topic|TopicShape $topic Body param: The `m.room.topic` event content for the room. + * @param string $type body param: The type of group to create + * @param string $username body param: The public username for the created group + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function createGroup( + string $groupType, + string $bridgeID, + ?string $loginID = null, + Avatar|array|null $avatar = null, + Disappear|array|null $disappear = null, + Name|array|null $name = null, + mixed $parent = null, + ?array $participants = null, + ?string $roomID = null, + Topic|array|null $topic = null, + ?string $type = null, + ?string $username = null, + RequestOptions|array|null $requestOptions = null, + ): RoomNewGroupResponse; +} diff --git a/src/ServiceContracts/Matrix/Bridges/RoomsRawContract.php b/src/ServiceContracts/Matrix/Bridges/RoomsRawContract.php new file mode 100644 index 0000000..8ee171d --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/RoomsRawContract.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateDmParams; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewDmResponse; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewGroupResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface RoomsRawContract +{ + /** + * @api + * + * @param string $identifier path param: The identifier to resolve or start a chat with + * @param array<string,mixed>|RoomCreateDmParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RoomNewDmResponse> + * + * @throws APIException + */ + public function createDm( + string $identifier, + array|RoomCreateDmParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $groupType path param: Group type to create + * @param array<string,mixed>|RoomCreateGroupParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RoomNewGroupResponse> + * + * @throws APIException + */ + public function createGroup( + string $groupType, + array|RoomCreateGroupParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/Bridges/UsersContract.php b/src/ServiceContracts/Matrix/Bridges/UsersContract.php new file mode 100644 index 0000000..2474d2d --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/UsersContract.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Bridges\Users\UserResolveResponse; +use BeeperDesktop\Matrix\Bridges\Users\UserSearchResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface UsersContract +{ + /** + * @api + * + * @param string $identifier path param: The identifier to resolve or start a chat with + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID query param: An optional explicit login ID to do the action through + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function resolve( + string $identifier, + string $bridgeID, + ?string $loginID = null, + RequestOptions|array|null $requestOptions = null, + ): UserResolveResponse; + + /** + * @api + * + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID query param: An optional explicit login ID to do the action through + * @param string $query Body param: The search query to send to the remote network + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function search( + string $bridgeID, + ?string $loginID = null, + ?string $query = null, + RequestOptions|array|null $requestOptions = null, + ): UserSearchResponse; +} diff --git a/src/ServiceContracts/Matrix/Bridges/UsersRawContract.php b/src/ServiceContracts/Matrix/Bridges/UsersRawContract.php new file mode 100644 index 0000000..7d6d745 --- /dev/null +++ b/src/ServiceContracts/Matrix/Bridges/UsersRawContract.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Bridges; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Bridges\Users\UserResolveParams; +use BeeperDesktop\Matrix\Bridges\Users\UserResolveResponse; +use BeeperDesktop\Matrix\Bridges\Users\UserSearchParams; +use BeeperDesktop\Matrix\Bridges\Users\UserSearchResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface UsersRawContract +{ + /** + * @api + * + * @param string $identifier path param: The identifier to resolve or start a chat with + * @param array<string,mixed>|UserResolveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UserResolveResponse> + * + * @throws APIException + */ + public function resolve( + string $identifier, + array|UserResolveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param array<string,mixed>|UserSearchParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UserSearchResponse> + * + * @throws APIException + */ + public function search( + string $bridgeID, + array|UserSearchParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/BridgesContract.php b/src/ServiceContracts/Matrix/BridgesContract.php new file mode 100644 index 0000000..e257f81 --- /dev/null +++ b/src/ServiceContracts/Matrix/BridgesContract.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix; + +interface BridgesContract {} diff --git a/src/ServiceContracts/Matrix/BridgesRawContract.php b/src/ServiceContracts/Matrix/BridgesRawContract.php new file mode 100644 index 0000000..32ce605 --- /dev/null +++ b/src/ServiceContracts/Matrix/BridgesRawContract.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix; + +interface BridgesRawContract {} diff --git a/src/ServiceContracts/Matrix/Rooms/AccountDataContract.php b/src/ServiceContracts/Matrix/Rooms/AccountDataContract.php new file mode 100644 index 0000000..8134cf3 --- /dev/null +++ b/src/ServiceContracts/Matrix/Rooms/AccountDataContract.php @@ -0,0 +1,54 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Rooms; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface AccountDataContract +{ + /** + * @api + * + * @param string $type The event type of the account data to get. Custom types should be + * namespaced to avoid clashes. + * @param string $userID The ID of the user to get account data for. The access token must be + * authorized to make requests for this user ID. + * @param string $roomID the ID of the room to get account data for + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieve( + string $type, + string $userID, + string $roomID, + RequestOptions|array|null $requestOptions = null, + ): mixed; + + /** + * @api + * + * @param string $type Path param: The event type of the account data to set. Custom types should be + * namespaced to avoid clashes. + * @param string $userID Path param: The ID of the user to set account data for. The access token must be + * authorized to make requests for this user ID. + * @param string $roomID path param: The ID of the room to set account data on + * @param mixed $body Body param + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function update( + string $type, + string $userID, + string $roomID, + mixed $body, + RequestOptions|array|null $requestOptions = null, + ): mixed; +} diff --git a/src/ServiceContracts/Matrix/Rooms/AccountDataRawContract.php b/src/ServiceContracts/Matrix/Rooms/AccountDataRawContract.php new file mode 100644 index 0000000..c54cba7 --- /dev/null +++ b/src/ServiceContracts/Matrix/Rooms/AccountDataRawContract.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Rooms; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\AccountData\AccountDataRetrieveParams; +use BeeperDesktop\Matrix\Rooms\AccountData\AccountDataUpdateParams; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface AccountDataRawContract +{ + /** + * @api + * + * @param string $type The event type of the account data to get. Custom types should be + * namespaced to avoid clashes. + * @param array<string,mixed>|AccountDataRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function retrieve( + string $type, + array|AccountDataRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $type Path param: The event type of the account data to set. Custom types should be + * namespaced to avoid clashes. + * @param array<string,mixed>|AccountDataUpdateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function update( + string $type, + array|AccountDataUpdateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/Rooms/EventsContract.php b/src/ServiceContracts/Matrix/Rooms/EventsContract.php new file mode 100644 index 0000000..fa0d1c1 --- /dev/null +++ b/src/ServiceContracts/Matrix/Rooms/EventsContract.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Rooms; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\Events\EventGetResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface EventsContract +{ + /** + * @api + * + * @param string $eventID the event ID to get + * @param string $roomID the ID of the room the event is in + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieve( + string $eventID, + string $roomID, + RequestOptions|array|null $requestOptions = null, + ): EventGetResponse; +} diff --git a/src/ServiceContracts/Matrix/Rooms/EventsRawContract.php b/src/ServiceContracts/Matrix/Rooms/EventsRawContract.php new file mode 100644 index 0000000..94cd95b --- /dev/null +++ b/src/ServiceContracts/Matrix/Rooms/EventsRawContract.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Rooms; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\Events\EventGetResponse; +use BeeperDesktop\Matrix\Rooms\Events\EventRetrieveParams; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface EventsRawContract +{ + /** + * @api + * + * @param string $eventID the event ID to get + * @param array<string,mixed>|EventRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<EventGetResponse> + * + * @throws APIException + */ + public function retrieve( + string $eventID, + array|EventRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/Rooms/StateContract.php b/src/ServiceContracts/Matrix/Rooms/StateContract.php new file mode 100644 index 0000000..ca2d54d --- /dev/null +++ b/src/ServiceContracts/Matrix/Rooms/StateContract.php @@ -0,0 +1,56 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Rooms; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\State\StateListResponseItem; +use BeeperDesktop\Matrix\Rooms\State\StateRetrieveParams\Format; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface StateContract +{ + /** + * @api + * + * @param string $stateKey Path param: The key of the state to look up. Defaults to an empty string. When + * an empty string, the trailing slash on this endpoint is optional. + * @param string $roomID path param: The room to look up the state in + * @param string $eventType path param: The type of state to look up + * @param Format|value-of<Format> $format Query param: 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. + * @param RequestOpts|null $requestOptions + * + * @return array<string,mixed> + * + * @throws APIException + */ + public function retrieve( + string $stateKey, + string $roomID, + string $eventType, + Format|string|null $format = null, + RequestOptions|array|null $requestOptions = null, + ): array; + + /** + * @api + * + * @param string $roomID the room to look up the state for + * @param RequestOpts|null $requestOptions + * + * @return list<StateListResponseItem> + * + * @throws APIException + */ + public function list( + string $roomID, + RequestOptions|array|null $requestOptions = null + ): array; +} diff --git a/src/ServiceContracts/Matrix/Rooms/StateRawContract.php b/src/ServiceContracts/Matrix/Rooms/StateRawContract.php new file mode 100644 index 0000000..85b3436 --- /dev/null +++ b/src/ServiceContracts/Matrix/Rooms/StateRawContract.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Rooms; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\State\StateListResponseItem; +use BeeperDesktop\Matrix\Rooms\State\StateRetrieveParams; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface StateRawContract +{ + /** + * @api + * + * @param string $stateKey Path param: The key of the state to look up. Defaults to an empty string. When + * an empty string, the trailing slash on this endpoint is optional. + * @param array<string,mixed>|StateRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<array<string,mixed>> + * + * @throws APIException + */ + public function retrieve( + string $stateKey, + array|StateRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $roomID the room to look up the state for + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<list<StateListResponseItem>> + * + * @throws APIException + */ + public function list( + string $roomID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/RoomsContract.php b/src/ServiceContracts/Matrix/RoomsContract.php new file mode 100644 index 0000000..610c005 --- /dev/null +++ b/src/ServiceContracts/Matrix/RoomsContract.php @@ -0,0 +1,147 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\InitialState; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Invite3pid; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Preset; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Visibility; +use BeeperDesktop\Matrix\Rooms\RoomJoinParams\ThirdPartySigned; +use BeeperDesktop\Matrix\Rooms\RoomJoinResponse; +use BeeperDesktop\Matrix\Rooms\RoomNewResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type InitialStateShape from \BeeperDesktop\Matrix\Rooms\RoomCreateParams\InitialState + * @phpstan-import-type Invite3pidShape from \BeeperDesktop\Matrix\Rooms\RoomCreateParams\Invite3pid + * @phpstan-import-type ThirdPartySignedShape from \BeeperDesktop\Matrix\Rooms\RoomJoinParams\ThirdPartySigned + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface RoomsContract +{ + /** + * @api + * + * @param mixed $creationContent 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. + * @param list<InitialState|InitialStateShape> $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. + * @param list<string> $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. + * @param list<Invite3pid|Invite3pidShape> $invite3pid a list of objects representing third-party IDs to invite into + * the room + * @param bool $isDirect 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. + * @param string $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`. + * @param mixed $powerLevelContentOverride 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. + * @param Preset|value-of<Preset> $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`. + * @param string $roomAliasName 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. + * @param string $roomVersion 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. + * @param string $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`. + * @param Visibility|value-of<Visibility> $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`. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function create( + mixed $creationContent = null, + ?array $initialState = null, + ?array $invite = null, + ?array $invite3pid = null, + ?bool $isDirect = null, + ?string $name = null, + mixed $powerLevelContentOverride = null, + Preset|string|null $preset = null, + ?string $roomAliasName = null, + ?string $roomVersion = null, + ?string $topic = null, + Visibility|string|null $visibility = null, + RequestOptions|array|null $requestOptions = null, + ): RoomNewResponse; + + /** + * @api + * + * @param string $roomIDOrAlias path param: The room identifier or alias to join + * @param list<string> $via Query param: The servers to attempt to join the room through. One of the servers + * must be participating in the room. + * @param string $reason body param: Optional reason to be included as the `reason` on the subsequent + * membership event + * @param ThirdPartySigned|ThirdPartySignedShape $thirdPartySigned Body param: 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. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function join( + string $roomIDOrAlias, + ?array $via = null, + ?string $reason = null, + ThirdPartySigned|array|null $thirdPartySigned = null, + RequestOptions|array|null $requestOptions = null, + ): RoomJoinResponse; + + /** + * @api + * + * @param string $roomID the room identifier to leave + * @param string $reason optional reason to be included as the `reason` on the subsequent + * membership event + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function leave( + string $roomID, + ?string $reason = null, + RequestOptions|array|null $requestOptions = null, + ): mixed; +} diff --git a/src/ServiceContracts/Matrix/RoomsRawContract.php b/src/ServiceContracts/Matrix/RoomsRawContract.php new file mode 100644 index 0000000..2fbfdf3 --- /dev/null +++ b/src/ServiceContracts/Matrix/RoomsRawContract.php @@ -0,0 +1,69 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams; +use BeeperDesktop\Matrix\Rooms\RoomJoinParams; +use BeeperDesktop\Matrix\Rooms\RoomJoinResponse; +use BeeperDesktop\Matrix\Rooms\RoomLeaveParams; +use BeeperDesktop\Matrix\Rooms\RoomNewResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface RoomsRawContract +{ + /** + * @api + * + * @param array<string,mixed>|RoomCreateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RoomNewResponse> + * + * @throws APIException + */ + public function create( + array|RoomCreateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $roomIDOrAlias path param: The room identifier or alias to join + * @param array<string,mixed>|RoomJoinParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RoomJoinResponse> + * + * @throws APIException + */ + public function join( + string $roomIDOrAlias, + array|RoomJoinParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $roomID the room identifier to leave + * @param array<string,mixed>|RoomLeaveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function leave( + string $roomID, + array|RoomLeaveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/Users/AccountDataContract.php b/src/ServiceContracts/Matrix/Users/AccountDataContract.php new file mode 100644 index 0000000..11b694b --- /dev/null +++ b/src/ServiceContracts/Matrix/Users/AccountDataContract.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Users; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface AccountDataContract +{ + /** + * @api + * + * @param string $type The event type of the account data to get. Custom types should be + * namespaced to avoid clashes. + * @param string $userID The ID of the user to get account data for. The access token must be + * authorized to make requests for this user ID. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieve( + string $type, + string $userID, + RequestOptions|array|null $requestOptions = null, + ): mixed; + + /** + * @api + * + * @param string $type Path param: The event type of the account data to set. Custom types should be + * namespaced to avoid clashes. + * @param string $userID Path param: The ID of the user to set account data for. The access token must be + * authorized to make requests for this user ID. + * @param mixed $body Body param + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function update( + string $type, + string $userID, + mixed $body, + RequestOptions|array|null $requestOptions = null, + ): mixed; +} diff --git a/src/ServiceContracts/Matrix/Users/AccountDataRawContract.php b/src/ServiceContracts/Matrix/Users/AccountDataRawContract.php new file mode 100644 index 0000000..e13c173 --- /dev/null +++ b/src/ServiceContracts/Matrix/Users/AccountDataRawContract.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix\Users; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Users\AccountData\AccountDataRetrieveParams; +use BeeperDesktop\Matrix\Users\AccountData\AccountDataUpdateParams; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface AccountDataRawContract +{ + /** + * @api + * + * @param string $type The event type of the account data to get. Custom types should be + * namespaced to avoid clashes. + * @param array<string,mixed>|AccountDataRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function retrieve( + string $type, + array|AccountDataRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; + + /** + * @api + * + * @param string $type Path param: The event type of the account data to set. Custom types should be + * namespaced to avoid clashes. + * @param array<string,mixed>|AccountDataUpdateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function update( + string $type, + array|AccountDataUpdateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse; +} diff --git a/src/ServiceContracts/Matrix/UsersContract.php b/src/ServiceContracts/Matrix/UsersContract.php new file mode 100644 index 0000000..86b86f9 --- /dev/null +++ b/src/ServiceContracts/Matrix/UsersContract.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix; + +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Users\UserGetProfileResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface UsersContract +{ + /** + * @api + * + * @param string $userID the user whose profile information to get + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieveProfile( + string $userID, + RequestOptions|array|null $requestOptions = null + ): UserGetProfileResponse; +} diff --git a/src/ServiceContracts/Matrix/UsersRawContract.php b/src/ServiceContracts/Matrix/UsersRawContract.php new file mode 100644 index 0000000..f320cfd --- /dev/null +++ b/src/ServiceContracts/Matrix/UsersRawContract.php @@ -0,0 +1,31 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts\Matrix; + +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Users\UserGetProfileResponse; +use BeeperDesktop\RequestOptions; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +interface UsersRawContract +{ + /** + * @api + * + * @param string $userID the user whose profile information to get + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UserGetProfileResponse> + * + * @throws APIException + */ + public function retrieveProfile( + string $userID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse; +} diff --git a/src/ServiceContracts/MatrixContract.php b/src/ServiceContracts/MatrixContract.php new file mode 100644 index 0000000..d4b8790 --- /dev/null +++ b/src/ServiceContracts/MatrixContract.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts; + +interface MatrixContract {} diff --git a/src/ServiceContracts/MatrixRawContract.php b/src/ServiceContracts/MatrixRawContract.php new file mode 100644 index 0000000..9532d3e --- /dev/null +++ b/src/ServiceContracts/MatrixRawContract.php @@ -0,0 +1,7 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\ServiceContracts; + +interface MatrixRawContract {} diff --git a/src/Services/App/E2ee/RecoveryCode/ResetRawService.php b/src/Services/App/E2ee/RecoveryCode/ResetRawService.php new file mode 100644 index 0000000..8252fc7 --- /dev/null +++ b/src/Services/App/E2ee/RecoveryCode/ResetRawService.php @@ -0,0 +1,91 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee\RecoveryCode; + +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetConfirmParams; +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetConfirmResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetCreateParams; +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetNewResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\RecoveryCode\ResetRawContract; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class ResetRawService implements ResetRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Create a new recovery key when the user cannot use the existing one. + * + * @param array{recoveryCode?: string}|ResetCreateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<ResetNewResponse> + * + * @throws APIException + */ + public function create( + array|ResetCreateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = ResetCreateParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/e2ee/recovery-code/reset', + body: (object) $parsed, + options: $options, + convert: ResetNewResponse::class, + ); + } + + /** + * @api + * + * Confirm that the new recovery key should be used for this account. + * + * @param array{recoveryCode: string}|ResetConfirmParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<ResetConfirmResponse> + * + * @throws APIException + */ + public function confirm( + array|ResetConfirmParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = ResetConfirmParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/e2ee/recovery-code/reset/confirm', + body: (object) $parsed, + options: $options, + convert: ResetConfirmResponse::class, + ); + } +} diff --git a/src/Services/App/E2ee/RecoveryCode/ResetService.php b/src/Services/App/E2ee/RecoveryCode/ResetService.php new file mode 100644 index 0000000..8b3c51a --- /dev/null +++ b/src/Services/App/E2ee/RecoveryCode/ResetService.php @@ -0,0 +1,78 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee\RecoveryCode; + +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetConfirmResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetNewResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\RecoveryCode\ResetContract; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class ResetService implements ResetContract +{ + /** + * @api + */ + public ResetRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new ResetRawService($client); + } + + /** + * @api + * + * Create a new recovery key when the user cannot use the existing one. + * + * @param string $recoveryCode existing recovery key, if the user has it + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function create( + ?string $recoveryCode = null, + RequestOptions|array|null $requestOptions = null, + ): ResetNewResponse { + $params = Util::removeNulls(['recoveryCode' => $recoveryCode]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->create(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Confirm that the new recovery key should be used for this account. + * + * @param string $recoveryCode new recovery key returned by the reset step + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function confirm( + string $recoveryCode, + RequestOptions|array|null $requestOptions = null + ): ResetConfirmResponse { + $params = Util::removeNulls(['recoveryCode' => $recoveryCode]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->confirm(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/App/E2ee/RecoveryCodeRawService.php b/src/Services/App/E2ee/RecoveryCodeRawService.php new file mode 100644 index 0000000..479734b --- /dev/null +++ b/src/Services/App/E2ee/RecoveryCodeRawService.php @@ -0,0 +1,82 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee; + +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeMarkBackedUpResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeVerifyParams; +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeVerifyResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\RecoveryCodeRawContract; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class RecoveryCodeRawService implements RecoveryCodeRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Record that the user saved their recovery key. + * + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RecoveryCodeMarkBackedUpResponse> + * + * @throws APIException + */ + public function markBackedUp( + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/e2ee/recovery-code/mark-backed-up', + options: $requestOptions, + convert: RecoveryCodeMarkBackedUpResponse::class, + ); + } + + /** + * @api + * + * Unlock encrypted messages with the user recovery key. + * + * @param array{recoveryCode: string}|RecoveryCodeVerifyParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RecoveryCodeVerifyResponse> + * + * @throws APIException + */ + public function verify( + array|RecoveryCodeVerifyParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = RecoveryCodeVerifyParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/e2ee/recovery-code/verify', + body: (object) $parsed, + options: $options, + convert: RecoveryCodeVerifyResponse::class, + ); + } +} diff --git a/src/Services/App/E2ee/RecoveryCodeService.php b/src/Services/App/E2ee/RecoveryCodeService.php new file mode 100644 index 0000000..7da0700 --- /dev/null +++ b/src/Services/App/E2ee/RecoveryCodeService.php @@ -0,0 +1,81 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee; + +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeMarkBackedUpResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeVerifyResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\RecoveryCodeContract; +use BeeperDesktop\Services\App\E2ee\RecoveryCode\ResetService; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class RecoveryCodeService implements RecoveryCodeContract +{ + /** + * @api + */ + public RecoveryCodeRawService $raw; + + /** + * @api + */ + public ResetService $reset; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new RecoveryCodeRawService($client); + $this->reset = new ResetService($client); + } + + /** + * @api + * + * Record that the user saved their recovery key. + * + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function markBackedUp( + RequestOptions|array|null $requestOptions = null + ): RecoveryCodeMarkBackedUpResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->markBackedUp(requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Unlock encrypted messages with the user recovery key. + * + * @param string $recoveryCode recovery key saved by the user + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function verify( + string $recoveryCode, + RequestOptions|array|null $requestOptions = null + ): RecoveryCodeVerifyResponse { + $params = Util::removeNulls(['recoveryCode' => $recoveryCode]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->verify(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/App/E2ee/Verification/QrRawService.php b/src/Services/App/E2ee/Verification/QrRawService.php new file mode 100644 index 0000000..d84db80 --- /dev/null +++ b/src/Services/App/E2ee/Verification/QrRawService.php @@ -0,0 +1,86 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Qr\QrConfirmScannedResponse; +use BeeperDesktop\App\E2ee\Verification\Qr\QrScanParams; +use BeeperDesktop\App\E2ee\Verification\Qr\QrScanResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\Verification\QrRawContract; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class QrRawService implements QrRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Confirm that another device scanned this device QR code. + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<QrConfirmScannedResponse> + * + * @throws APIException + */ + public function confirmScanned( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: [ + 'v1/app/e2ee/verification/%1$s/qr/confirm-scanned', $verificationID, + ], + options: $requestOptions, + convert: QrConfirmScannedResponse::class, + ); + } + + /** + * @api + * + * Submit the QR code scanned from another signed-in device. + * + * @param array{data: string}|QrScanParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<QrScanResponse> + * + * @throws APIException + */ + public function scan( + array|QrScanParams $params, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + [$parsed, $options] = QrScanParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/e2ee/verification/qr/scan', + body: (object) $parsed, + options: $options, + convert: QrScanResponse::class, + ); + } +} diff --git a/src/Services/App/E2ee/Verification/QrService.php b/src/Services/App/E2ee/Verification/QrService.php new file mode 100644 index 0000000..ea7d147 --- /dev/null +++ b/src/Services/App/E2ee/Verification/QrService.php @@ -0,0 +1,76 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Qr\QrConfirmScannedResponse; +use BeeperDesktop\App\E2ee\Verification\Qr\QrScanResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\Verification\QrContract; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class QrService implements QrContract +{ + /** + * @api + */ + public QrRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new QrRawService($client); + } + + /** + * @api + * + * Confirm that another device scanned this device QR code. + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function confirmScanned( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): QrConfirmScannedResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->confirmScanned($verificationID, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Submit the QR code scanned from another signed-in device. + * + * @param string $data QR code payload scanned from the other device + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function scan( + string $data, + RequestOptions|array|null $requestOptions = null + ): QrScanResponse { + $params = Util::removeNulls(['data' => $data]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->scan(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/App/E2ee/Verification/SasRawService.php b/src/Services/App/E2ee/Verification/SasRawService.php new file mode 100644 index 0000000..bc16293 --- /dev/null +++ b/src/Services/App/E2ee/Verification/SasRawService.php @@ -0,0 +1,77 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Sas\SaConfirmResponse; +use BeeperDesktop\App\E2ee\Verification\Sas\SaStartResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\Verification\SasRawContract; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class SasRawService implements SasRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Confirm that the emoji or number sequence matches on both devices. + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<SaConfirmResponse> + * + * @throws APIException + */ + public function confirm( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/app/e2ee/verification/%1$s/sas/confirm', $verificationID], + options: $requestOptions, + convert: SaConfirmResponse::class, + ); + } + + /** + * @api + * + * Start emoji comparison for device verification. + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<SaStartResponse> + * + * @throws APIException + */ + public function start( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/app/e2ee/verification/%1$s/sas/start', $verificationID], + options: $requestOptions, + convert: SaStartResponse::class, + ); + } +} diff --git a/src/Services/App/E2ee/Verification/SasService.php b/src/Services/App/E2ee/Verification/SasService.php new file mode 100644 index 0000000..e772944 --- /dev/null +++ b/src/Services/App/E2ee/Verification/SasService.php @@ -0,0 +1,73 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Sas\SaConfirmResponse; +use BeeperDesktop\App\E2ee\Verification\Sas\SaStartResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\Verification\SasContract; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class SasService implements SasContract +{ + /** + * @api + */ + public SasRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new SasRawService($client); + } + + /** + * @api + * + * Confirm that the emoji or number sequence matches on both devices. + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function confirm( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): SaConfirmResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->confirm($verificationID, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Start emoji comparison for device verification. + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function start( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): SaStartResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->start($verificationID, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/App/E2ee/VerificationRawService.php b/src/Services/App/E2ee/VerificationRawService.php new file mode 100644 index 0000000..da8dc6e --- /dev/null +++ b/src/Services/App/E2ee/VerificationRawService.php @@ -0,0 +1,119 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee; + +use BeeperDesktop\App\E2ee\Verification\VerificationAcceptResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationCancelParams; +use BeeperDesktop\App\E2ee\Verification\VerificationCancelResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationCreateParams; +use BeeperDesktop\App\E2ee\Verification\VerificationNewResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\VerificationRawContract; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class VerificationRawService implements VerificationRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Start verifying this device from another signed-in device. + * + * @param array{userID?: string}|VerificationCreateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<VerificationNewResponse> + * + * @throws APIException + */ + public function create( + array|VerificationCreateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = VerificationCreateParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/e2ee/verification', + body: (object) $parsed, + options: $options, + convert: VerificationNewResponse::class, + ); + } + + /** + * @api + * + * Accept an incoming device verification request. + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<VerificationAcceptResponse> + * + * @throws APIException + */ + public function accept( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/app/e2ee/verification/%1$s/accept', $verificationID], + options: $requestOptions, + convert: VerificationAcceptResponse::class, + ); + } + + /** + * @api + * + * Cancel an active device verification request. + * + * @param string $verificationID verification ID + * @param array{code?: string, reason?: string}|VerificationCancelParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<VerificationCancelResponse> + * + * @throws APIException + */ + public function cancel( + string $verificationID, + array|VerificationCancelParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = VerificationCancelParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['v1/app/e2ee/verification/%1$s/cancel', $verificationID], + body: (object) $parsed, + options: $options, + convert: VerificationCancelResponse::class, + ); + } +} diff --git a/src/Services/App/E2ee/VerificationService.php b/src/Services/App/E2ee/VerificationService.php new file mode 100644 index 0000000..131f0d4 --- /dev/null +++ b/src/Services/App/E2ee/VerificationService.php @@ -0,0 +1,117 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App\E2ee; + +use BeeperDesktop\App\E2ee\Verification\VerificationAcceptResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationCancelResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationNewResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\E2ee\VerificationContract; +use BeeperDesktop\Services\App\E2ee\Verification\QrService; +use BeeperDesktop\Services\App\E2ee\Verification\SasService; + +/** + * First-party sign-in and encrypted messaging setup for Beeper Desktop. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class VerificationService implements VerificationContract +{ + /** + * @api + */ + public VerificationRawService $raw; + + /** + * @api + */ + public QrService $qr; + + /** + * @api + */ + public SasService $sas; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new VerificationRawService($client); + $this->qr = new QrService($client); + $this->sas = new SasService($client); + } + + /** + * @api + * + * Start verifying this device from another signed-in device. + * + * @param string $userID User ID to verify. Defaults to the signed-in user. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function create( + ?string $userID = null, + RequestOptions|array|null $requestOptions = null + ): VerificationNewResponse { + $params = Util::removeNulls(['userID' => $userID]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->create(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Accept an incoming device verification request. + * + * @param string $verificationID verification ID + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function accept( + string $verificationID, + RequestOptions|array|null $requestOptions = null + ): VerificationAcceptResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->accept($verificationID, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Cancel an active device verification request. + * + * @param string $verificationID verification ID + * @param string $code optional cancellation code + * @param string $reason optional user-facing cancellation reason + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function cancel( + string $verificationID, + ?string $code = null, + ?string $reason = null, + RequestOptions|array|null $requestOptions = null, + ): VerificationCancelResponse { + $params = Util::removeNulls(['code' => $code, 'reason' => $reason]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->cancel($verificationID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/App/E2eeRawService.php b/src/Services/App/E2eeRawService.php new file mode 100644 index 0000000..68f4710 --- /dev/null +++ b/src/Services/App/E2eeRawService.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App; + +use BeeperDesktop\Client; +use BeeperDesktop\ServiceContracts\App\E2eeRawContract; + +/** + * Manage encrypted messaging setup. + */ +final class E2eeRawService implements E2eeRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} +} diff --git a/src/Services/App/E2eeService.php b/src/Services/App/E2eeService.php new file mode 100644 index 0000000..838a87b --- /dev/null +++ b/src/Services/App/E2eeService.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App; + +use BeeperDesktop\Client; +use BeeperDesktop\ServiceContracts\App\E2eeContract; +use BeeperDesktop\Services\App\E2ee\RecoveryCodeService; +use BeeperDesktop\Services\App\E2ee\VerificationService; + +/** + * Manage encrypted messaging setup. + */ +final class E2eeService implements E2eeContract +{ + /** + * @api + */ + public E2eeRawService $raw; + + /** + * @api + */ + public RecoveryCodeService $recoveryCode; + + /** + * @api + */ + public VerificationService $verification; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new E2eeRawService($client); + $this->recoveryCode = new RecoveryCodeService($client); + $this->verification = new VerificationService($client); + } +} diff --git a/src/Services/App/LoginRawService.php b/src/Services/App/LoginRawService.php new file mode 100644 index 0000000..580c9ea --- /dev/null +++ b/src/Services/App/LoginRawService.php @@ -0,0 +1,155 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App; + +use BeeperDesktop\App\Login\LoginEmailParams; +use BeeperDesktop\App\Login\LoginRegisterParams; +use BeeperDesktop\App\Login\LoginRegisterResponse; +use BeeperDesktop\App\Login\LoginResponseParams; +use BeeperDesktop\App\Login\LoginResponseResponse; +use BeeperDesktop\App\Login\LoginResponseResponse\UnionMember0; +use BeeperDesktop\App\Login\LoginResponseResponse\UnionMember1; +use BeeperDesktop\App\Login\LoginStartResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\LoginRawContract; + +/** + * Complete first-party Beeper app login. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class LoginRawService implements LoginRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Send a sign-in code to the user email address. + * + * @param array{email: string, request: string}|LoginEmailParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function email( + array|LoginEmailParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = LoginEmailParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/login/email', + body: (object) $parsed, + options: $options, + convert: 'mixed', + security: [], + ); + } + + /** + * @api + * + * Create a Beeper account after the user chooses a username and accepts the Terms of Use. + * + * @param array{ + * acceptTerms: bool, leadToken: string, request: string, username: string + * }|LoginRegisterParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<LoginRegisterResponse> + * + * @throws APIException + */ + public function register( + array|LoginRegisterParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = LoginRegisterParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/login/register', + body: (object) $parsed, + options: $options, + convert: LoginRegisterResponse::class, + security: [], + ); + } + + /** + * @api + * + * 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. + * + * @param array{request: string, response: string}|LoginResponseParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UnionMember0|UnionMember1> + * + * @throws APIException + */ + public function response( + array|LoginResponseParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = LoginResponseParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/login/response', + body: (object) $parsed, + options: $options, + convert: LoginResponseResponse::class, + security: [], + ); + } + + /** + * @api + * + * Start a first-party Beeper Desktop sign-in session. + * + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<LoginStartResponse> + * + * @throws APIException + */ + public function start( + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: 'v1/app/login/start', + options: $requestOptions, + convert: LoginStartResponse::class, + security: [], + ); + } +} diff --git a/src/Services/App/LoginService.php b/src/Services/App/LoginService.php new file mode 100644 index 0000000..07a5128 --- /dev/null +++ b/src/Services/App/LoginService.php @@ -0,0 +1,139 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\App; + +use BeeperDesktop\App\Login\LoginRegisterResponse; +use BeeperDesktop\App\Login\LoginResponseResponse\UnionMember0; +use BeeperDesktop\App\Login\LoginResponseResponse\UnionMember1; +use BeeperDesktop\App\Login\LoginStartResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\App\LoginContract; + +/** + * Complete first-party Beeper app login. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class LoginService implements LoginContract +{ + /** + * @api + */ + public LoginRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new LoginRawService($client); + } + + /** + * @api + * + * Send a sign-in code to the user email address. + * + * @param string $email email address to send the sign-in code to + * @param string $request login request ID returned by the start step + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function email( + string $email, + string $request, + RequestOptions|array|null $requestOptions = null, + ): mixed { + $params = Util::removeNulls(['email' => $email, 'request' => $request]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->email(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Create a Beeper account after the user chooses a username and accepts the Terms of Use. + * + * @param bool $acceptTerms confirms that the user accepted the Terms of Use and acknowledged the Privacy Policy + * @param string $leadToken registration token returned by Beeper + * @param string $request login request ID returned by the start step + * @param string $username username selected by the user + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function register( + bool $acceptTerms, + string $leadToken, + string $request, + string $username, + RequestOptions|array|null $requestOptions = null, + ): LoginRegisterResponse { + $params = Util::removeNulls( + [ + 'acceptTerms' => $acceptTerms, + 'leadToken' => $leadToken, + 'request' => $request, + 'username' => $username, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->register(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * 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. + * + * @param string $request login request ID returned by the start step + * @param string $response sign-in code from the user email + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function response( + string $request, + string $response, + RequestOptions|array|null $requestOptions = null, + ): UnionMember0|UnionMember1 { + $params = Util::removeNulls( + ['request' => $request, 'response' => $response] + ); + + // @phpstan-ignore-next-line argument.type + $response1 = $this->raw->response(params: $params, requestOptions: $requestOptions); + + return $response1->parse(); + } + + /** + * @api + * + * Start a first-party Beeper Desktop sign-in session. + * + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function start( + RequestOptions|array|null $requestOptions = null + ): LoginStartResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->start(requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/AppRawService.php b/src/Services/AppRawService.php new file mode 100644 index 0000000..fb7bbad --- /dev/null +++ b/src/Services/AppRawService.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services; + +use BeeperDesktop\App\AppStatusResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\AppRawContract; + +/** + * Manage Beeper app login and encrypted messaging setup. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class AppRawService implements AppRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * 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. + * + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AppStatusResponse> + * + * @throws APIException + */ + public function status( + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: 'v1/app/status', + options: $requestOptions, + convert: AppStatusResponse::class, + ); + } +} diff --git a/src/Services/AppService.php b/src/Services/AppService.php new file mode 100644 index 0000000..1863933 --- /dev/null +++ b/src/Services/AppService.php @@ -0,0 +1,64 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services; + +use BeeperDesktop\App\AppStatusResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\AppContract; +use BeeperDesktop\Services\App\E2eeService; +use BeeperDesktop\Services\App\LoginService; + +/** + * Manage Beeper app login and encrypted messaging setup. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class AppService implements AppContract +{ + /** + * @api + */ + public AppRawService $raw; + + /** + * @api + */ + public LoginService $login; + + /** + * @api + */ + public E2eeService $e2ee; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new AppRawService($client); + $this->login = new LoginService($client); + $this->e2ee = new E2eeService($client); + } + + /** + * @api + * + * 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. + * + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function status( + RequestOptions|array|null $requestOptions = null + ): AppStatusResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->status(requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/BridgesRawService.php b/src/Services/BridgesRawService.php new file mode 100644 index 0000000..723e9eb --- /dev/null +++ b/src/Services/BridgesRawService.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services; + +use BeeperDesktop\Bridges\BridgeListResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\BridgesRawContract; + +/** + * Manage bridge-backed account types and account availability. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class BridgesRawService implements BridgesRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * 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. + * + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<BridgeListResponse> + * + * @throws APIException + */ + public function list( + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: 'v1/bridges', + options: $requestOptions, + convert: BridgeListResponse::class, + ); + } +} diff --git a/src/Services/BridgesService.php b/src/Services/BridgesService.php new file mode 100644 index 0000000..af8e652 --- /dev/null +++ b/src/Services/BridgesService.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services; + +use BeeperDesktop\Bridges\BridgeListResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\BridgesContract; + +/** + * Manage bridge-backed account types and account availability. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class BridgesService implements BridgesContract +{ + /** + * @api + */ + public BridgesRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new BridgesRawService($client); + } + + /** + * @api + * + * 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. + * + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function list( + RequestOptions|array|null $requestOptions = null + ): BridgeListResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->list(requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/Bridges/AuthRawService.php b/src/Services/Matrix/Bridges/AuthRawService.php new file mode 100644 index 0000000..400d005 --- /dev/null +++ b/src/Services/Matrix/Bridges/AuthRawService.php @@ -0,0 +1,358 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListFlowsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListLoginsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthLogoutParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember3; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepParams; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\AuthRawContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class AuthRawService implements AuthRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Get the available login flows. + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AuthListFlowsResponse> + * + * @throws APIException + */ + public function listFlows( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/login/flows', + $bridgeID, + ], + options: $requestOptions, + convert: AuthListFlowsResponse::class, + ); + } + + /** + * @api + * + * Get the login IDs of the current user. + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AuthListLoginsResponse> + * + * @throws APIException + */ + public function listLogins( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/logins', + $bridgeID, + ], + options: $requestOptions, + convert: AuthListLoginsResponse::class, + ); + } + + /** + * @api + * + * Log out of an existing login. + * + * @param string $loginID The unique ID of a login. Defined by the network connector. + * @param array{bridgeID: string}|AuthLogoutParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function logout( + string $loginID, + array|AuthLogoutParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = AuthLogoutParams::parseRequest( + $params, + $requestOptions, + ); + $bridgeID = $parsed['bridgeID']; + unset($parsed['bridgeID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/logout/%2$s', + $bridgeID, + $loginID, + ], + options: $options, + convert: 'mixed', + ); + } + + /** + * @api + * + * 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. + * + * @param string $flowID path param: The login flow ID to use + * @param array{bridgeID: string, loginID?: string}|AuthStartLoginParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UnionMember0|UnionMember1|UnionMember2|UnionMember3> + * + * @throws APIException + */ + public function startLogin( + string $flowID, + array|AuthStartLoginParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = AuthStartLoginParams::parseRequest( + $params, + $requestOptions, + ); + $bridgeID = $parsed['bridgeID']; + unset($parsed['bridgeID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/login/start/%2$s', + $bridgeID, + $flowID, + ], + query: Util::array_transform_keys($parsed, ['loginID' => 'login_id']), + options: $options, + convert: AuthStartLoginResponse::class, + ); + } + + /** + * @api + * + * Submit extracted cookies in a login process. + * + * @param string $stepID path param: The ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param array{ + * bridgeID: string, loginProcessID: string, body: array<string,string> + * }|AuthSubmitCookiesParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AuthSubmitCookiesResponse\UnionMember0|AuthSubmitCookiesResponse\UnionMember1|AuthSubmitCookiesResponse\UnionMember2|AuthSubmitCookiesResponse\UnionMember3,> + * + * @throws APIException + */ + public function submitCookies( + string $stepID, + array|AuthSubmitCookiesParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = AuthSubmitCookiesParams::parseRequest( + $params, + $requestOptions, + ); + $bridgeID = $parsed['bridgeID']; + unset($parsed['bridgeID']); + $loginProcessID = $parsed['loginProcessID']; + unset($parsed['loginProcessID']); + + /** @var array<string,mixed> */ + $body = $parsed['body']; + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/login/step/%2$s/%3$s/cookies', + $bridgeID, + $loginProcessID, + $stepID, + ], + body: array_diff_key($body, array_flip(['bridgeID', 'loginProcessID'])), + options: $options, + convert: AuthSubmitCookiesResponse::class, + ); + } + + /** + * @api + * + * Submit user input in a login process. + * + * @param string $stepID path param: The ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param array{ + * bridgeID: string, loginProcessID: string, body: array<string,string> + * }|AuthSubmitUserInputParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AuthSubmitUserInputResponse\UnionMember0|AuthSubmitUserInputResponse\UnionMember1|AuthSubmitUserInputResponse\UnionMember2|AuthSubmitUserInputResponse\UnionMember3,> + * + * @throws APIException + */ + public function submitUserInput( + string $stepID, + array|AuthSubmitUserInputParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = AuthSubmitUserInputParams::parseRequest( + $params, + $requestOptions, + ); + $bridgeID = $parsed['bridgeID']; + unset($parsed['bridgeID']); + $loginProcessID = $parsed['loginProcessID']; + unset($parsed['loginProcessID']); + + /** @var array<string,mixed> */ + $body = $parsed['body']; + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/login/step/%2$s/%3$s/user_input', + $bridgeID, + $loginProcessID, + $stepID, + ], + body: array_diff_key($body, array_flip(['bridgeID', 'loginProcessID'])), + options: $options, + convert: AuthSubmitUserInputResponse::class, + ); + } + + /** + * @api + * + * Wait for the next step after displaying data to the user. + * + * @param string $stepID the ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param array{ + * bridgeID: string, loginProcessID: string + * }|AuthWaitForStepParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AuthWaitForStepResponse\UnionMember0|AuthWaitForStepResponse\UnionMember1|AuthWaitForStepResponse\UnionMember2|AuthWaitForStepResponse\UnionMember3,> + * + * @throws APIException + */ + public function waitForStep( + string $stepID, + array|AuthWaitForStepParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = AuthWaitForStepParams::parseRequest( + $params, + $requestOptions, + ); + $bridgeID = $parsed['bridgeID']; + unset($parsed['bridgeID']); + $loginProcessID = $parsed['loginProcessID']; + unset($parsed['loginProcessID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/login/step/%2$s/%3$s/display_and_wait', + $bridgeID, + $loginProcessID, + $stepID, + ], + options: $options, + convert: AuthWaitForStepResponse::class, + ); + } + + /** + * @api + * + * 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 + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<AuthWhoamiResponse> + * + * @throws APIException + */ + public function whoami( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/whoami', + $bridgeID, + ], + options: $requestOptions, + convert: AuthWhoamiResponse::class, + ); + } +} diff --git a/src/Services/Matrix/Bridges/AuthService.php b/src/Services/Matrix/Bridges/AuthService.php new file mode 100644 index 0000000..f43223c --- /dev/null +++ b/src/Services/Matrix/Bridges/AuthService.php @@ -0,0 +1,265 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListFlowsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListLoginsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember0; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember1; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember2; +use BeeperDesktop\Matrix\Bridges\Auth\AuthStartLoginResponse\UnionMember3; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\AuthContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class AuthService implements AuthContract +{ + /** + * @api + */ + public AuthRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new AuthRawService($client); + } + + /** + * @api + * + * Get the available login flows. + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function listFlows( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): AuthListFlowsResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->listFlows($bridgeID, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Get the login IDs of the current user. + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function listLogins( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): AuthListLoginsResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->listLogins($bridgeID, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Log out of an existing login. + * + * @param string $loginID The unique ID of a login. Defined by the network connector. + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function logout( + string $loginID, + string $bridgeID, + RequestOptions|array|null $requestOptions = null, + ): mixed { + $params = Util::removeNulls(['bridgeID' => $bridgeID]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->logout($loginID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * 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. + * + * @param string $flowID path param: The login flow ID to use + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID Query param: 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. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function startLogin( + string $flowID, + string $bridgeID, + ?string $loginID = null, + RequestOptions|array|null $requestOptions = null, + ): UnionMember0|UnionMember1|UnionMember2|UnionMember3 { + $params = Util::removeNulls( + ['bridgeID' => $bridgeID, 'loginID' => $loginID] + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->startLogin($flowID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Submit extracted cookies in a login process. + * + * @param string $stepID path param: The ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginProcessID path param: The ID of the login process, as returned in the `login_id` field of the start call + * @param array<string,string> $body Body param + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function submitCookies( + string $stepID, + string $bridgeID, + string $loginProcessID, + array $body, + RequestOptions|array|null $requestOptions = null, + ): \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember0|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember1|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember2|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitCookiesResponse\UnionMember3 { + $params = Util::removeNulls( + [ + 'bridgeID' => $bridgeID, + 'loginProcessID' => $loginProcessID, + 'body' => $body, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->submitCookies($stepID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Submit user input in a login process. + * + * @param string $stepID path param: The ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginProcessID path param: The ID of the login process, as returned in the `login_id` field of the start call + * @param array<string,string> $body Body param + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function submitUserInput( + string $stepID, + string $bridgeID, + string $loginProcessID, + array $body, + RequestOptions|array|null $requestOptions = null, + ): \BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember0|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember1|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember2|\BeeperDesktop\Matrix\Bridges\Auth\AuthSubmitUserInputResponse\UnionMember3 { + $params = Util::removeNulls( + [ + 'bridgeID' => $bridgeID, + 'loginProcessID' => $loginProcessID, + 'body' => $body, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->submitUserInput($stepID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Wait for the next step after displaying data to the user. + * + * @param string $stepID the ID of the step being submitted, as returned in the `step_id` field of the start call or the previous submit call + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginProcessID the ID of the login process, as returned in the `login_id` field of the start call + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function waitForStep( + string $stepID, + string $bridgeID, + string $loginProcessID, + RequestOptions|array|null $requestOptions = null, + ): \BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember0|\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember1|\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember2|\BeeperDesktop\Matrix\Bridges\Auth\AuthWaitForStepResponse\UnionMember3 { + $params = Util::removeNulls( + ['bridgeID' => $bridgeID, 'loginProcessID' => $loginProcessID] + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->waitForStep($stepID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * 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 + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function whoami( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): AuthWhoamiResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->whoami($bridgeID, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/Bridges/CapabilitiesRawService.php b/src/Services/Matrix/Bridges/CapabilitiesRawService.php new file mode 100644 index 0000000..5bb6999 --- /dev/null +++ b/src/Services/Matrix/Bridges/CapabilitiesRawService.php @@ -0,0 +1,54 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Conversion\MapOf; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\CapabilitiesRawContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class CapabilitiesRawService implements CapabilitiesRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Get bridge capabilities + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<array<string,mixed>> + * + * @throws APIException + */ + public function retrieve( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/capabilities', + $bridgeID, + ], + options: $requestOptions, + convert: new MapOf('mixed'), + ); + } +} diff --git a/src/Services/Matrix/Bridges/CapabilitiesService.php b/src/Services/Matrix/Bridges/CapabilitiesService.php new file mode 100644 index 0000000..8b7533e --- /dev/null +++ b/src/Services/Matrix/Bridges/CapabilitiesService.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\CapabilitiesContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class CapabilitiesService implements CapabilitiesContract +{ + /** + * @api + */ + public CapabilitiesRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new CapabilitiesRawService($client); + } + + /** + * @api + * + * Get bridge capabilities + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param RequestOpts|null $requestOptions + * + * @return array<string,mixed> + * + * @throws APIException + */ + public function retrieve( + string $bridgeID, + RequestOptions|array|null $requestOptions = null + ): array { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->retrieve($bridgeID, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/Bridges/ContactsRawService.php b/src/Services/Matrix/Bridges/ContactsRawService.php new file mode 100644 index 0000000..89e89dc --- /dev/null +++ b/src/Services/Matrix/Bridges/ContactsRawService.php @@ -0,0 +1,64 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Contacts\ContactListParams; +use BeeperDesktop\Matrix\Bridges\Contacts\ContactListResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\ContactsRawContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class ContactsRawService implements ContactsRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Get a list of contacts. + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param array{loginID?: string}|ContactListParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<ContactListResponse> + * + * @throws APIException + */ + public function list( + string $bridgeID, + array|ContactListParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = ContactListParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/contacts', + $bridgeID, + ], + query: Util::array_transform_keys($parsed, ['loginID' => 'login_id']), + options: $options, + convert: ContactListResponse::class, + ); + } +} diff --git a/src/Services/Matrix/Bridges/ContactsService.php b/src/Services/Matrix/Bridges/ContactsService.php new file mode 100644 index 0000000..2a62427 --- /dev/null +++ b/src/Services/Matrix/Bridges/ContactsService.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Contacts\ContactListResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\ContactsContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class ContactsService implements ContactsContract +{ + /** + * @api + */ + public ContactsRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new ContactsRawService($client); + } + + /** + * @api + * + * Get a list of contacts. + * + * @param string $bridgeID bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID an optional explicit login ID to do the action through + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function list( + string $bridgeID, + ?string $loginID = null, + RequestOptions|array|null $requestOptions = null, + ): ContactListResponse { + $params = Util::removeNulls(['loginID' => $loginID]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->list($bridgeID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/Bridges/RoomsRawService.php b/src/Services/Matrix/Bridges/RoomsRawService.php new file mode 100644 index 0000000..3c72509 --- /dev/null +++ b/src/Services/Matrix/Bridges/RoomsRawService.php @@ -0,0 +1,136 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateDmParams; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Avatar; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Disappear; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Name; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Topic; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewDmResponse; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewGroupResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\RoomsRawContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type AvatarShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Avatar + * @phpstan-import-type DisappearShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Disappear + * @phpstan-import-type NameShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Name + * @phpstan-import-type TopicShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Topic + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class RoomsRawService implements RoomsRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Create a direct chat with a user on the remote network. + * + * @param string $identifier path param: The identifier to resolve or start a chat with + * @param array{bridgeID: string, loginID?: string}|RoomCreateDmParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RoomNewDmResponse> + * + * @throws APIException + */ + public function createDm( + string $identifier, + array|RoomCreateDmParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = RoomCreateDmParams::parseRequest( + $params, + $requestOptions, + ); + $bridgeID = $parsed['bridgeID']; + unset($parsed['bridgeID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/create_dm/%2$s', + $bridgeID, + $identifier, + ], + query: Util::array_transform_keys($parsed, ['loginID' => 'login_id']), + options: $options, + convert: RoomNewDmResponse::class, + ); + } + + /** + * @api + * + * Create a group chat on the remote network. + * + * @param string $groupType path param: Group type to create + * @param array{ + * bridgeID: string, + * loginID?: string, + * avatar?: Avatar|AvatarShape, + * disappear?: Disappear|DisappearShape, + * name?: Name|NameShape, + * parent?: mixed, + * participants?: list<string>, + * roomID?: string, + * topic?: Topic|TopicShape, + * type?: string, + * username?: string, + * }|RoomCreateGroupParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RoomNewGroupResponse> + * + * @throws APIException + */ + public function createGroup( + string $groupType, + array|RoomCreateGroupParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = RoomCreateGroupParams::parseRequest( + $params, + $requestOptions, + ); + $bridgeID = $parsed['bridgeID']; + unset($parsed['bridgeID']); + $query_params = array_flip(['loginID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/create_group/%2$s', + $bridgeID, + $groupType, + ], + query: Util::array_transform_keys( + array_intersect_key($parsed, $query_params), + ['loginID' => 'login_id'] + ), + body: (object) array_diff_key( + array_diff_key($parsed, $query_params), + array_flip(['bridgeID']) + ), + options: $options, + convert: RoomNewGroupResponse::class, + ); + } +} diff --git a/src/Services/Matrix/Bridges/RoomsService.php b/src/Services/Matrix/Bridges/RoomsService.php new file mode 100644 index 0000000..62d086f --- /dev/null +++ b/src/Services/Matrix/Bridges/RoomsService.php @@ -0,0 +1,129 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Avatar; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Disappear; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Name; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Topic; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewDmResponse; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewGroupResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\RoomsContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type AvatarShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Avatar + * @phpstan-import-type DisappearShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Disappear + * @phpstan-import-type NameShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Name + * @phpstan-import-type TopicShape from \BeeperDesktop\Matrix\Bridges\Rooms\RoomCreateGroupParams\Topic + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class RoomsService implements RoomsContract +{ + /** + * @api + */ + public RoomsRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new RoomsRawService($client); + } + + /** + * @api + * + * Create a direct chat with a user on the remote network. + * + * @param string $identifier path param: The identifier to resolve or start a chat with + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID query param: An optional explicit login ID to do the action through + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function createDm( + string $identifier, + string $bridgeID, + ?string $loginID = null, + RequestOptions|array|null $requestOptions = null, + ): RoomNewDmResponse { + $params = Util::removeNulls( + ['bridgeID' => $bridgeID, 'loginID' => $loginID] + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->createDm($identifier, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Create a group chat on the remote network. + * + * @param string $groupType path param: Group type to create + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID query param: An optional explicit login ID to do the action through + * @param Avatar|AvatarShape $avatar Body param: The `m.room.avatar` event content for the room. + * @param Disappear|DisappearShape $disappear Body param: The `com.beeper.disappearing_timer` event content for the room. + * @param Name|NameShape $name Body param: The `m.room.name` event content for the room. + * @param mixed $parent Body param + * @param list<string> $participants body param: The users to add to the group initially + * @param string $roomID Body param: An existing Matrix room ID to bridge to. + * The other parameters must be already in sync with the room state when using this parameter. + * @param Topic|TopicShape $topic Body param: The `m.room.topic` event content for the room. + * @param string $type body param: The type of group to create + * @param string $username body param: The public username for the created group + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function createGroup( + string $groupType, + string $bridgeID, + ?string $loginID = null, + Avatar|array|null $avatar = null, + Disappear|array|null $disappear = null, + Name|array|null $name = null, + mixed $parent = null, + ?array $participants = null, + ?string $roomID = null, + Topic|array|null $topic = null, + ?string $type = null, + ?string $username = null, + RequestOptions|array|null $requestOptions = null, + ): RoomNewGroupResponse { + $params = Util::removeNulls( + [ + 'bridgeID' => $bridgeID, + 'loginID' => $loginID, + 'avatar' => $avatar, + 'disappear' => $disappear, + 'name' => $name, + 'parent' => $parent, + 'participants' => $participants, + 'roomID' => $roomID, + 'topic' => $topic, + 'type' => $type, + 'username' => $username, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->createGroup($groupType, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/Bridges/UsersRawService.php b/src/Services/Matrix/Bridges/UsersRawService.php new file mode 100644 index 0000000..ca51575 --- /dev/null +++ b/src/Services/Matrix/Bridges/UsersRawService.php @@ -0,0 +1,110 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Users\UserResolveParams; +use BeeperDesktop\Matrix\Bridges\Users\UserResolveResponse; +use BeeperDesktop\Matrix\Bridges\Users\UserSearchParams; +use BeeperDesktop\Matrix\Bridges\Users\UserSearchResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\UsersRawContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class UsersRawService implements UsersRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Resolve an identifier to a user on the remote network. + * + * @param string $identifier path param: The identifier to resolve or start a chat with + * @param array{bridgeID: string, loginID?: string}|UserResolveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UserResolveResponse> + * + * @throws APIException + */ + public function resolve( + string $identifier, + array|UserResolveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = UserResolveParams::parseRequest( + $params, + $requestOptions, + ); + $bridgeID = $parsed['bridgeID']; + unset($parsed['bridgeID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/resolve_identifier/%2$s', + $bridgeID, + $identifier, + ], + query: Util::array_transform_keys($parsed, ['loginID' => 'login_id']), + options: $options, + convert: UserResolveResponse::class, + ); + } + + /** + * @api + * + * Search for users on the remote network + * + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param array{loginID?: string, query?: string}|UserSearchParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UserSearchResponse> + * + * @throws APIException + */ + public function search( + string $bridgeID, + array|UserSearchParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = UserSearchParams::parseRequest( + $params, + $requestOptions, + ); + $query_params = array_flip(['loginID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: [ + '_matrix/client/unstable/com.beeper.bridge/%1$s/_matrix/provision/v3/search_users', + $bridgeID, + ], + query: Util::array_transform_keys( + array_intersect_key($parsed, $query_params), + ['loginID' => 'login_id'] + ), + body: (object) array_diff_key($parsed, $query_params), + options: $options, + convert: UserSearchResponse::class, + ); + } +} diff --git a/src/Services/Matrix/Bridges/UsersService.php b/src/Services/Matrix/Bridges/UsersService.php new file mode 100644 index 0000000..2d81169 --- /dev/null +++ b/src/Services/Matrix/Bridges/UsersService.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Users\UserResolveResponse; +use BeeperDesktop\Matrix\Bridges\Users\UserSearchResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Bridges\UsersContract; + +/** + * Matrix-compatible APIs for accounts and connected network bridges. + * + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class UsersService implements UsersContract +{ + /** + * @api + */ + public UsersRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new UsersRawService($client); + } + + /** + * @api + * + * Resolve an identifier to a user on the remote network. + * + * @param string $identifier path param: The identifier to resolve or start a chat with + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID query param: An optional explicit login ID to do the action through + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function resolve( + string $identifier, + string $bridgeID, + ?string $loginID = null, + RequestOptions|array|null $requestOptions = null, + ): UserResolveResponse { + $params = Util::removeNulls( + ['bridgeID' => $bridgeID, 'loginID' => $loginID] + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->resolve($identifier, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Search for users on the remote network + * + * @param string $bridgeID path param: Bridge ID for the connected network account, for example discordgo or local-whatsapp + * @param string $loginID query param: An optional explicit login ID to do the action through + * @param string $query Body param: The search query to send to the remote network + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function search( + string $bridgeID, + ?string $loginID = null, + ?string $query = null, + RequestOptions|array|null $requestOptions = null, + ): UserSearchResponse { + $params = Util::removeNulls(['loginID' => $loginID, 'query' => $query]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->search($bridgeID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/BridgesRawService.php b/src/Services/Matrix/BridgesRawService.php new file mode 100644 index 0000000..ff19408 --- /dev/null +++ b/src/Services/Matrix/BridgesRawService.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix; + +use BeeperDesktop\Client; +use BeeperDesktop\ServiceContracts\Matrix\BridgesRawContract; + +/** + * Matrix-compatible APIs for connected network bridges. + */ +final class BridgesRawService implements BridgesRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} +} diff --git a/src/Services/Matrix/BridgesService.php b/src/Services/Matrix/BridgesService.php new file mode 100644 index 0000000..e66dcf8 --- /dev/null +++ b/src/Services/Matrix/BridgesService.php @@ -0,0 +1,62 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix; + +use BeeperDesktop\Client; +use BeeperDesktop\ServiceContracts\Matrix\BridgesContract; +use BeeperDesktop\Services\Matrix\Bridges\AuthService; +use BeeperDesktop\Services\Matrix\Bridges\CapabilitiesService; +use BeeperDesktop\Services\Matrix\Bridges\ContactsService; +use BeeperDesktop\Services\Matrix\Bridges\RoomsService; +use BeeperDesktop\Services\Matrix\Bridges\UsersService; + +/** + * Matrix-compatible APIs for connected network bridges. + */ +final class BridgesService implements BridgesContract +{ + /** + * @api + */ + public BridgesRawService $raw; + + /** + * @api + */ + public AuthService $auth; + + /** + * @api + */ + public ContactsService $contacts; + + /** + * @api + */ + public UsersService $users; + + /** + * @api + */ + public RoomsService $rooms; + + /** + * @api + */ + public CapabilitiesService $capabilities; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new BridgesRawService($client); + $this->auth = new AuthService($client); + $this->contacts = new ContactsService($client); + $this->users = new UsersService($client); + $this->rooms = new RoomsService($client); + $this->capabilities = new CapabilitiesService($client); + } +} diff --git a/src/Services/Matrix/Rooms/AccountDataRawService.php b/src/Services/Matrix/Rooms/AccountDataRawService.php new file mode 100644 index 0000000..1a51dcc --- /dev/null +++ b/src/Services/Matrix/Rooms/AccountDataRawService.php @@ -0,0 +1,118 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Rooms; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\AccountData\AccountDataRetrieveParams; +use BeeperDesktop\Matrix\Rooms\AccountData\AccountDataUpdateParams; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Rooms\AccountDataRawContract; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class AccountDataRawService implements AccountDataRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Get some account data for the client on a given room. This config is only + * visible to the user that set the account data. + * + * @param string $type The event type of the account data to get. Custom types should be + * namespaced to avoid clashes. + * @param array{userID: string, roomID: string}|AccountDataRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function retrieve( + string $type, + array|AccountDataRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = AccountDataRetrieveParams::parseRequest( + $params, + $requestOptions, + ); + $userID = $parsed['userID']; + unset($parsed['userID']); + $roomID = $parsed['roomID']; + unset($parsed['roomID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: [ + '_matrix/client/v3/user/%1$s/rooms/%2$s/account_data/%3$s', + $userID, + $roomID, + $type, + ], + options: $options, + convert: 'mixed', + ); + } + + /** + * @api + * + * 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). + * + * @param string $type Path param: The event type of the account data to set. Custom types should be + * namespaced to avoid clashes. + * @param array{ + * userID: string, roomID: string, body: mixed + * }|AccountDataUpdateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function update( + string $type, + array|AccountDataUpdateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = AccountDataUpdateParams::parseRequest( + $params, + $requestOptions, + ); + $userID = $parsed['userID']; + unset($parsed['userID']); + $roomID = $parsed['roomID']; + unset($parsed['roomID']); + + /** @var array<string,mixed> */ + $body = $parsed['body']; + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'put', + path: [ + '_matrix/client/v3/user/%1$s/rooms/%2$s/account_data/%3$s', + $userID, + $roomID, + $type, + ], + body: array_diff_key($body, array_flip(['userID', 'roomID'])), + options: $options, + convert: 'mixed', + ); + } +} diff --git a/src/Services/Matrix/Rooms/AccountDataService.php b/src/Services/Matrix/Rooms/AccountDataService.php new file mode 100644 index 0000000..9deb961 --- /dev/null +++ b/src/Services/Matrix/Rooms/AccountDataService.php @@ -0,0 +1,93 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Rooms; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Rooms\AccountDataContract; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class AccountDataService implements AccountDataContract +{ + /** + * @api + */ + public AccountDataRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new AccountDataRawService($client); + } + + /** + * @api + * + * Get some account data for the client on a given room. This config is only + * visible to the user that set the account data. + * + * @param string $type The event type of the account data to get. Custom types should be + * namespaced to avoid clashes. + * @param string $userID The ID of the user to get account data for. The access token must be + * authorized to make requests for this user ID. + * @param string $roomID the ID of the room to get account data for + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieve( + string $type, + string $userID, + string $roomID, + RequestOptions|array|null $requestOptions = null, + ): mixed { + $params = Util::removeNulls(['userID' => $userID, 'roomID' => $roomID]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->retrieve($type, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * 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). + * + * @param string $type Path param: The event type of the account data to set. Custom types should be + * namespaced to avoid clashes. + * @param string $userID Path param: The ID of the user to set account data for. The access token must be + * authorized to make requests for this user ID. + * @param string $roomID path param: The ID of the room to set account data on + * @param mixed $body Body param + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function update( + string $type, + string $userID, + string $roomID, + mixed $body, + RequestOptions|array|null $requestOptions = null, + ): mixed { + $params = Util::removeNulls( + ['userID' => $userID, 'roomID' => $roomID, 'body' => $body] + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->update($type, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/Rooms/EventsRawService.php b/src/Services/Matrix/Rooms/EventsRawService.php new file mode 100644 index 0000000..e778993 --- /dev/null +++ b/src/Services/Matrix/Rooms/EventsRawService.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Rooms; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\Events\EventGetResponse; +use BeeperDesktop\Matrix\Rooms\Events\EventRetrieveParams; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Rooms\EventsRawContract; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class EventsRawService implements EventsRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * 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. + * + * @param string $eventID the event ID to get + * @param array{roomID: string}|EventRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<EventGetResponse> + * + * @throws APIException + */ + public function retrieve( + string $eventID, + array|EventRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = EventRetrieveParams::parseRequest( + $params, + $requestOptions, + ); + $roomID = $parsed['roomID']; + unset($parsed['roomID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: ['_matrix/client/v3/rooms/%1$s/event/%2$s', $roomID, $eventID], + options: $options, + convert: EventGetResponse::class, + ); + } +} diff --git a/src/Services/Matrix/Rooms/EventsService.php b/src/Services/Matrix/Rooms/EventsService.php new file mode 100644 index 0000000..82a9800 --- /dev/null +++ b/src/Services/Matrix/Rooms/EventsService.php @@ -0,0 +1,56 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Rooms; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Rooms\Events\EventGetResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Rooms\EventsContract; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class EventsService implements EventsContract +{ + /** + * @api + */ + public EventsRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new EventsRawService($client); + } + + /** + * @api + * + * 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. + * + * @param string $eventID the event ID to get + * @param string $roomID the ID of the room the event is in + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieve( + string $eventID, + string $roomID, + RequestOptions|array|null $requestOptions = null, + ): EventGetResponse { + $params = Util::removeNulls(['roomID' => $roomID]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->retrieve($eventID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/Rooms/StateRawService.php b/src/Services/Matrix/Rooms/StateRawService.php new file mode 100644 index 0000000..27ae98f --- /dev/null +++ b/src/Services/Matrix/Rooms/StateRawService.php @@ -0,0 +1,101 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Rooms; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Conversion\ListOf; +use BeeperDesktop\Core\Conversion\MapOf; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\State\StateListResponseItem; +use BeeperDesktop\Matrix\Rooms\State\StateRetrieveParams; +use BeeperDesktop\Matrix\Rooms\State\StateRetrieveParams\Format; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Rooms\StateRawContract; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class StateRawService implements StateRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * 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. + * + * @param string $stateKey Path param: The key of the state to look up. Defaults to an empty string. When + * an empty string, the trailing slash on this endpoint is optional. + * @param array{ + * roomID: string, eventType: string, format?: Format|value-of<Format> + * }|StateRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<array<string,mixed>> + * + * @throws APIException + */ + public function retrieve( + string $stateKey, + array|StateRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = StateRetrieveParams::parseRequest( + $params, + $requestOptions, + ); + $roomID = $parsed['roomID']; + unset($parsed['roomID']); + $eventType = $parsed['eventType']; + unset($parsed['eventType']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: [ + '_matrix/client/v3/rooms/%1$s/state/%2$s/%3$s', + $roomID, + $eventType, + $stateKey, + ], + query: $parsed, + options: $options, + convert: new MapOf('mixed'), + ); + } + + /** + * @api + * + * Get the state events for the current state of a room. + * + * @param string $roomID the room to look up the state for + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<list<StateListResponseItem>> + * + * @throws APIException + */ + public function list( + string $roomID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: ['_matrix/client/v3/rooms/%1$s/state', $roomID], + options: $requestOptions, + convert: new ListOf(StateListResponseItem::class), + ); + } +} diff --git a/src/Services/Matrix/Rooms/StateService.php b/src/Services/Matrix/Rooms/StateService.php new file mode 100644 index 0000000..57d1ed6 --- /dev/null +++ b/src/Services/Matrix/Rooms/StateService.php @@ -0,0 +1,93 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Rooms; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Rooms\State\StateListResponseItem; +use BeeperDesktop\Matrix\Rooms\State\StateRetrieveParams\Format; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Rooms\StateContract; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class StateService implements StateContract +{ + /** + * @api + */ + public StateRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new StateRawService($client); + } + + /** + * @api + * + * 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. + * + * @param string $stateKey Path param: The key of the state to look up. Defaults to an empty string. When + * an empty string, the trailing slash on this endpoint is optional. + * @param string $roomID path param: The room to look up the state in + * @param string $eventType path param: The type of state to look up + * @param Format|value-of<Format> $format Query param: 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. + * @param RequestOpts|null $requestOptions + * + * @return array<string,mixed> + * + * @throws APIException + */ + public function retrieve( + string $stateKey, + string $roomID, + string $eventType, + Format|string|null $format = null, + RequestOptions|array|null $requestOptions = null, + ): array { + $params = Util::removeNulls( + ['roomID' => $roomID, 'eventType' => $eventType, 'format' => $format] + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->retrieve($stateKey, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * Get the state events for the current state of a room. + * + * @param string $roomID the room to look up the state for + * @param RequestOpts|null $requestOptions + * + * @return list<StateListResponseItem> + * + * @throws APIException + */ + public function list( + string $roomID, + RequestOptions|array|null $requestOptions = null + ): array { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->list($roomID, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/RoomsRawService.php b/src/Services/Matrix/RoomsRawService.php new file mode 100644 index 0000000..91d2425 --- /dev/null +++ b/src/Services/Matrix/RoomsRawService.php @@ -0,0 +1,232 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\InitialState; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Invite3pid; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Preset; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Visibility; +use BeeperDesktop\Matrix\Rooms\RoomJoinParams; +use BeeperDesktop\Matrix\Rooms\RoomJoinParams\ThirdPartySigned; +use BeeperDesktop\Matrix\Rooms\RoomJoinResponse; +use BeeperDesktop\Matrix\Rooms\RoomLeaveParams; +use BeeperDesktop\Matrix\Rooms\RoomNewResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\RoomsRawContract; + +/** + * @phpstan-import-type InitialStateShape from \BeeperDesktop\Matrix\Rooms\RoomCreateParams\InitialState + * @phpstan-import-type Invite3pidShape from \BeeperDesktop\Matrix\Rooms\RoomCreateParams\Invite3pid + * @phpstan-import-type ThirdPartySignedShape from \BeeperDesktop\Matrix\Rooms\RoomJoinParams\ThirdPartySigned + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class RoomsRawService implements RoomsRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * 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`. + * + * @param array{ + * creationContent?: mixed, + * initialState?: list<InitialState|InitialStateShape>, + * invite?: list<string>, + * invite3pid?: list<Invite3pid|Invite3pidShape>, + * isDirect?: bool, + * name?: string, + * powerLevelContentOverride?: mixed, + * preset?: Preset|value-of<Preset>, + * roomAliasName?: string, + * roomVersion?: string, + * topic?: string, + * visibility?: Visibility|value-of<Visibility>, + * }|RoomCreateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RoomNewResponse> + * + * @throws APIException + */ + public function create( + array|RoomCreateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = RoomCreateParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: '_matrix/client/v3/createRoom', + body: (object) $parsed, + options: $options, + convert: RoomNewResponse::class, + ); + } + + /** + * @api + * + * *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. + * + * @param string $roomIDOrAlias path param: The room identifier or alias to join + * @param array{ + * via?: list<string>, + * reason?: string, + * thirdPartySigned?: ThirdPartySigned|ThirdPartySignedShape, + * }|RoomJoinParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<RoomJoinResponse> + * + * @throws APIException + */ + public function join( + string $roomIDOrAlias, + array|RoomJoinParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = RoomJoinParams::parseRequest( + $params, + $requestOptions, + ); + $query_params = array_flip(['via']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['_matrix/client/v3/join/%1$s', $roomIDOrAlias], + query: array_intersect_key($parsed, $query_params), + body: (object) array_diff_key($parsed, $query_params), + options: $options, + convert: RoomJoinResponse::class, + ); + } + + /** + * @api + * + * 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. + * + * @param string $roomID the room identifier to leave + * @param array{reason?: string}|RoomLeaveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function leave( + string $roomID, + array|RoomLeaveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = RoomLeaveParams::parseRequest( + $params, + $requestOptions, + ); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'post', + path: ['_matrix/client/v3/rooms/%1$s/leave', $roomID], + body: (object) $parsed, + options: $options, + convert: 'mixed', + ); + } +} diff --git a/src/Services/Matrix/RoomsService.php b/src/Services/Matrix/RoomsService.php new file mode 100644 index 0000000..8b75a91 --- /dev/null +++ b/src/Services/Matrix/RoomsService.php @@ -0,0 +1,312 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\InitialState; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Invite3pid; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Preset; +use BeeperDesktop\Matrix\Rooms\RoomCreateParams\Visibility; +use BeeperDesktop\Matrix\Rooms\RoomJoinParams\ThirdPartySigned; +use BeeperDesktop\Matrix\Rooms\RoomJoinResponse; +use BeeperDesktop\Matrix\Rooms\RoomNewResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\RoomsContract; +use BeeperDesktop\Services\Matrix\Rooms\AccountDataService; +use BeeperDesktop\Services\Matrix\Rooms\EventsService; +use BeeperDesktop\Services\Matrix\Rooms\StateService; + +/** + * @phpstan-import-type InitialStateShape from \BeeperDesktop\Matrix\Rooms\RoomCreateParams\InitialState + * @phpstan-import-type Invite3pidShape from \BeeperDesktop\Matrix\Rooms\RoomCreateParams\Invite3pid + * @phpstan-import-type ThirdPartySignedShape from \BeeperDesktop\Matrix\Rooms\RoomJoinParams\ThirdPartySigned + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class RoomsService implements RoomsContract +{ + /** + * @api + */ + public RoomsRawService $raw; + + /** + * @api + */ + public AccountDataService $accountData; + + /** + * @api + */ + public StateService $state; + + /** + * @api + */ + public EventsService $events; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new RoomsRawService($client); + $this->accountData = new AccountDataService($client); + $this->state = new StateService($client); + $this->events = new EventsService($client); + } + + /** + * @api + * + * 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`. + * + * @param mixed $creationContent 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. + * @param list<InitialState|InitialStateShape> $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. + * @param list<string> $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. + * @param list<Invite3pid|Invite3pidShape> $invite3pid a list of objects representing third-party IDs to invite into + * the room + * @param bool $isDirect 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. + * @param string $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`. + * @param mixed $powerLevelContentOverride 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. + * @param Preset|value-of<Preset> $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`. + * @param string $roomAliasName 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. + * @param string $roomVersion 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. + * @param string $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`. + * @param Visibility|value-of<Visibility> $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`. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function create( + mixed $creationContent = null, + ?array $initialState = null, + ?array $invite = null, + ?array $invite3pid = null, + ?bool $isDirect = null, + ?string $name = null, + mixed $powerLevelContentOverride = null, + Preset|string|null $preset = null, + ?string $roomAliasName = null, + ?string $roomVersion = null, + ?string $topic = null, + Visibility|string|null $visibility = null, + RequestOptions|array|null $requestOptions = null, + ): RoomNewResponse { + $params = Util::removeNulls( + [ + 'creationContent' => $creationContent, + 'initialState' => $initialState, + 'invite' => $invite, + 'invite3pid' => $invite3pid, + 'isDirect' => $isDirect, + 'name' => $name, + 'powerLevelContentOverride' => $powerLevelContentOverride, + 'preset' => $preset, + 'roomAliasName' => $roomAliasName, + 'roomVersion' => $roomVersion, + 'topic' => $topic, + 'visibility' => $visibility, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->create(params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * *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. + * + * @param string $roomIDOrAlias path param: The room identifier or alias to join + * @param list<string> $via Query param: The servers to attempt to join the room through. One of the servers + * must be participating in the room. + * @param string $reason body param: Optional reason to be included as the `reason` on the subsequent + * membership event + * @param ThirdPartySigned|ThirdPartySignedShape $thirdPartySigned Body param: 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. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function join( + string $roomIDOrAlias, + ?array $via = null, + ?string $reason = null, + ThirdPartySigned|array|null $thirdPartySigned = null, + RequestOptions|array|null $requestOptions = null, + ): RoomJoinResponse { + $params = Util::removeNulls( + [ + 'via' => $via, + 'reason' => $reason, + 'thirdPartySigned' => $thirdPartySigned, + ], + ); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->join($roomIDOrAlias, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * 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. + * + * @param string $roomID the room identifier to leave + * @param string $reason optional reason to be included as the `reason` on the subsequent + * membership event + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function leave( + string $roomID, + ?string $reason = null, + RequestOptions|array|null $requestOptions = null, + ): mixed { + $params = Util::removeNulls(['reason' => $reason]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->leave($roomID, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/Users/AccountDataRawService.php b/src/Services/Matrix/Users/AccountDataRawService.php new file mode 100644 index 0000000..cbf92e1 --- /dev/null +++ b/src/Services/Matrix/Users/AccountDataRawService.php @@ -0,0 +1,103 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Users; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Users\AccountData\AccountDataRetrieveParams; +use BeeperDesktop\Matrix\Users\AccountData\AccountDataUpdateParams; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Users\AccountDataRawContract; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class AccountDataRawService implements AccountDataRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Get some account data for the client. This config is only visible to the user + * that set the account data. + * + * @param string $type The event type of the account data to get. Custom types should be + * namespaced to avoid clashes. + * @param array{userID: string}|AccountDataRetrieveParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function retrieve( + string $type, + array|AccountDataRetrieveParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = AccountDataRetrieveParams::parseRequest( + $params, + $requestOptions, + ); + $userID = $parsed['userID']; + unset($parsed['userID']); + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: ['_matrix/client/v3/user/%1$s/account_data/%2$s', $userID, $type], + options: $options, + convert: 'mixed', + ); + } + + /** + * @api + * + * 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). + * + * @param string $type Path param: The event type of the account data to set. Custom types should be + * namespaced to avoid clashes. + * @param array{userID: string, body: mixed}|AccountDataUpdateParams $params + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<mixed> + * + * @throws APIException + */ + public function update( + string $type, + array|AccountDataUpdateParams $params, + RequestOptions|array|null $requestOptions = null, + ): BaseResponse { + [$parsed, $options] = AccountDataUpdateParams::parseRequest( + $params, + $requestOptions, + ); + $userID = $parsed['userID']; + unset($parsed['userID']); + + /** @var array<string,mixed> */ + $body = $parsed['body']; + + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'put', + path: ['_matrix/client/v3/user/%1$s/account_data/%2$s', $userID, $type], + body: array_diff_key($body, array_flip(['userID'])), + options: $options, + convert: 'mixed', + ); + } +} diff --git a/src/Services/Matrix/Users/AccountDataService.php b/src/Services/Matrix/Users/AccountDataService.php new file mode 100644 index 0000000..6aec9cf --- /dev/null +++ b/src/Services/Matrix/Users/AccountDataService.php @@ -0,0 +1,88 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix\Users; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Core\Util; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\Users\AccountDataContract; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class AccountDataService implements AccountDataContract +{ + /** + * @api + */ + public AccountDataRawService $raw; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new AccountDataRawService($client); + } + + /** + * @api + * + * Get some account data for the client. This config is only visible to the user + * that set the account data. + * + * @param string $type The event type of the account data to get. Custom types should be + * namespaced to avoid clashes. + * @param string $userID The ID of the user to get account data for. The access token must be + * authorized to make requests for this user ID. + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieve( + string $type, + string $userID, + RequestOptions|array|null $requestOptions = null, + ): mixed { + $params = Util::removeNulls(['userID' => $userID]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->retrieve($type, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } + + /** + * @api + * + * 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). + * + * @param string $type Path param: The event type of the account data to set. Custom types should be + * namespaced to avoid clashes. + * @param string $userID Path param: The ID of the user to set account data for. The access token must be + * authorized to make requests for this user ID. + * @param mixed $body Body param + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function update( + string $type, + string $userID, + mixed $body, + RequestOptions|array|null $requestOptions = null, + ): mixed { + $params = Util::removeNulls(['userID' => $userID, 'body' => $body]); + + // @phpstan-ignore-next-line argument.type + $response = $this->raw->update($type, params: $params, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/Matrix/UsersRawService.php b/src/Services/Matrix/UsersRawService.php new file mode 100644 index 0000000..a03d0ca --- /dev/null +++ b/src/Services/Matrix/UsersRawService.php @@ -0,0 +1,49 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Contracts\BaseResponse; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Users\UserGetProfileResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\UsersRawContract; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class UsersRawService implements UsersRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} + + /** + * @api + * + * Get the complete profile for a user. + * + * @param string $userID the user whose profile information to get + * @param RequestOpts|null $requestOptions + * + * @return BaseResponse<UserGetProfileResponse> + * + * @throws APIException + */ + public function retrieveProfile( + string $userID, + RequestOptions|array|null $requestOptions = null + ): BaseResponse { + // @phpstan-ignore-next-line return.type + return $this->client->request( + method: 'get', + path: ['_matrix/client/v3/profile/%1$s', $userID], + options: $requestOptions, + convert: UserGetProfileResponse::class, + ); + } +} diff --git a/src/Services/Matrix/UsersService.php b/src/Services/Matrix/UsersService.php new file mode 100644 index 0000000..684b4d3 --- /dev/null +++ b/src/Services/Matrix/UsersService.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services\Matrix; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Exceptions\APIException; +use BeeperDesktop\Matrix\Users\UserGetProfileResponse; +use BeeperDesktop\RequestOptions; +use BeeperDesktop\ServiceContracts\Matrix\UsersContract; +use BeeperDesktop\Services\Matrix\Users\AccountDataService; + +/** + * @phpstan-import-type RequestOpts from \BeeperDesktop\RequestOptions + */ +final class UsersService implements UsersContract +{ + /** + * @api + */ + public UsersRawService $raw; + + /** + * @api + */ + public AccountDataService $accountData; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new UsersRawService($client); + $this->accountData = new AccountDataService($client); + } + + /** + * @api + * + * Get the complete profile for a user. + * + * @param string $userID the user whose profile information to get + * @param RequestOpts|null $requestOptions + * + * @throws APIException + */ + public function retrieveProfile( + string $userID, + RequestOptions|array|null $requestOptions = null + ): UserGetProfileResponse { + // @phpstan-ignore-next-line argument.type + $response = $this->raw->retrieveProfile($userID, requestOptions: $requestOptions); + + return $response->parse(); + } +} diff --git a/src/Services/MatrixRawService.php b/src/Services/MatrixRawService.php new file mode 100644 index 0000000..42c2e4e --- /dev/null +++ b/src/Services/MatrixRawService.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services; + +use BeeperDesktop\Client; +use BeeperDesktop\ServiceContracts\MatrixRawContract; + +/** + * Matrix-compatible APIs for accounts, rooms, and connected network bridges. + */ +final class MatrixRawService implements MatrixRawContract +{ + // @phpstan-ignore-next-line + /** + * @internal + */ + public function __construct(private Client $client) {} +} diff --git a/src/Services/MatrixService.php b/src/Services/MatrixService.php new file mode 100644 index 0000000..b29bc6a --- /dev/null +++ b/src/Services/MatrixService.php @@ -0,0 +1,48 @@ +<?php + +declare(strict_types=1); + +namespace BeeperDesktop\Services; + +use BeeperDesktop\Client; +use BeeperDesktop\ServiceContracts\MatrixContract; +use BeeperDesktop\Services\Matrix\BridgesService; +use BeeperDesktop\Services\Matrix\RoomsService; +use BeeperDesktop\Services\Matrix\UsersService; + +/** + * Matrix-compatible APIs for accounts, rooms, and connected network bridges. + */ +final class MatrixService implements MatrixContract +{ + /** + * @api + */ + public MatrixRawService $raw; + + /** + * @api + */ + public UsersService $users; + + /** + * @api + */ + public RoomsService $rooms; + + /** + * @api + */ + public BridgesService $bridges; + + /** + * @internal + */ + public function __construct(private Client $client) + { + $this->raw = new MatrixRawService($client); + $this->users = new UsersService($client); + $this->rooms = new RoomsService($client); + $this->bridges = new BridgesService($client); + } +} diff --git a/tests/Services/App/E2ee/RecoveryCode/ResetTest.php b/tests/Services/App/E2ee/RecoveryCode/ResetTest.php new file mode 100644 index 0000000..2eb9b2f --- /dev/null +++ b/tests/Services/App/E2ee/RecoveryCode/ResetTest.php @@ -0,0 +1,61 @@ +<?php + +namespace Tests\Services\App\E2ee\RecoveryCode; + +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetConfirmResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\Reset\ResetNewResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class ResetTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testCreate(): void + { + $result = $this->client->app->e2ee->recoveryCode->reset->create(); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(ResetNewResponse::class, $result); + } + + #[Test] + public function testConfirm(): void + { + $result = $this->client->app->e2ee->recoveryCode->reset->confirm( + recoveryCode: 'x' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(ResetConfirmResponse::class, $result); + } + + #[Test] + public function testConfirmWithOptionalParams(): void + { + $result = $this->client->app->e2ee->recoveryCode->reset->confirm( + recoveryCode: 'x' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(ResetConfirmResponse::class, $result); + } +} diff --git a/tests/Services/App/E2ee/RecoveryCodeTest.php b/tests/Services/App/E2ee/RecoveryCodeTest.php new file mode 100644 index 0000000..5f44f48 --- /dev/null +++ b/tests/Services/App/E2ee/RecoveryCodeTest.php @@ -0,0 +1,57 @@ +<?php + +namespace Tests\Services\App\E2ee; + +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeMarkBackedUpResponse; +use BeeperDesktop\App\E2ee\RecoveryCode\RecoveryCodeVerifyResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class RecoveryCodeTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testMarkBackedUp(): void + { + $result = $this->client->app->e2ee->recoveryCode->markBackedUp(); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(RecoveryCodeMarkBackedUpResponse::class, $result); + } + + #[Test] + public function testVerify(): void + { + $result = $this->client->app->e2ee->recoveryCode->verify(recoveryCode: 'x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(RecoveryCodeVerifyResponse::class, $result); + } + + #[Test] + public function testVerifyWithOptionalParams(): void + { + $result = $this->client->app->e2ee->recoveryCode->verify(recoveryCode: 'x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(RecoveryCodeVerifyResponse::class, $result); + } +} diff --git a/tests/Services/App/E2ee/Verification/QrTest.php b/tests/Services/App/E2ee/Verification/QrTest.php new file mode 100644 index 0000000..4f736a3 --- /dev/null +++ b/tests/Services/App/E2ee/Verification/QrTest.php @@ -0,0 +1,57 @@ +<?php + +namespace Tests\Services\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Qr\QrConfirmScannedResponse; +use BeeperDesktop\App\E2ee\Verification\Qr\QrScanResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class QrTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testConfirmScanned(): void + { + $result = $this->client->app->e2ee->verification->qr->confirmScanned('x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(QrConfirmScannedResponse::class, $result); + } + + #[Test] + public function testScan(): void + { + $result = $this->client->app->e2ee->verification->qr->scan(data: 'x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(QrScanResponse::class, $result); + } + + #[Test] + public function testScanWithOptionalParams(): void + { + $result = $this->client->app->e2ee->verification->qr->scan(data: 'x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(QrScanResponse::class, $result); + } +} diff --git a/tests/Services/App/E2ee/Verification/SasTest.php b/tests/Services/App/E2ee/Verification/SasTest.php new file mode 100644 index 0000000..5f942d8 --- /dev/null +++ b/tests/Services/App/E2ee/Verification/SasTest.php @@ -0,0 +1,48 @@ +<?php + +namespace Tests\Services\App\E2ee\Verification; + +use BeeperDesktop\App\E2ee\Verification\Sas\SaConfirmResponse; +use BeeperDesktop\App\E2ee\Verification\Sas\SaStartResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class SasTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testConfirm(): void + { + $result = $this->client->app->e2ee->verification->sas->confirm('x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(SaConfirmResponse::class, $result); + } + + #[Test] + public function testStart(): void + { + $result = $this->client->app->e2ee->verification->sas->start('x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(SaStartResponse::class, $result); + } +} diff --git a/tests/Services/App/E2ee/VerificationTest.php b/tests/Services/App/E2ee/VerificationTest.php new file mode 100644 index 0000000..329d057 --- /dev/null +++ b/tests/Services/App/E2ee/VerificationTest.php @@ -0,0 +1,58 @@ +<?php + +namespace Tests\Services\App\E2ee; + +use BeeperDesktop\App\E2ee\Verification\VerificationAcceptResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationCancelResponse; +use BeeperDesktop\App\E2ee\Verification\VerificationNewResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class VerificationTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testCreate(): void + { + $result = $this->client->app->e2ee->verification->create(); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(VerificationNewResponse::class, $result); + } + + #[Test] + public function testAccept(): void + { + $result = $this->client->app->e2ee->verification->accept('x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(VerificationAcceptResponse::class, $result); + } + + #[Test] + public function testCancel(): void + { + $result = $this->client->app->e2ee->verification->cancel('x'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(VerificationCancelResponse::class, $result); + } +} diff --git a/tests/Services/App/LoginTest.php b/tests/Services/App/LoginTest.php new file mode 100644 index 0000000..b52c2df --- /dev/null +++ b/tests/Services/App/LoginTest.php @@ -0,0 +1,115 @@ +<?php + +namespace Tests\Services\App; + +use BeeperDesktop\App\Login\LoginRegisterResponse; +use BeeperDesktop\App\Login\LoginStartResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class LoginTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testEmail(): void + { + $result = $this->client->app->login->email( + email: 'dev@stainless.com', + request: 'request' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testEmailWithOptionalParams(): void + { + $result = $this->client->app->login->email( + email: 'dev@stainless.com', + request: 'request' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testRegister(): void + { + $result = $this->client->app->login->register( + acceptTerms: true, + leadToken: 'leadToken', + request: 'request', + username: 'x', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(LoginRegisterResponse::class, $result); + } + + #[Test] + public function testRegisterWithOptionalParams(): void + { + $result = $this->client->app->login->register( + acceptTerms: true, + leadToken: 'leadToken', + request: 'request', + username: 'x', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(LoginRegisterResponse::class, $result); + } + + #[Test] + public function testResponse(): void + { + $result = $this->client->app->login->response( + request: 'request', + response: 'response' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testResponseWithOptionalParams(): void + { + $result = $this->client->app->login->response( + request: 'request', + response: 'response' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testStart(): void + { + $result = $this->client->app->login->start(); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(LoginStartResponse::class, $result); + } +} diff --git a/tests/Services/AppTest.php b/tests/Services/AppTest.php new file mode 100644 index 0000000..1ea8c5b --- /dev/null +++ b/tests/Services/AppTest.php @@ -0,0 +1,38 @@ +<?php + +namespace Tests\Services; + +use BeeperDesktop\App\AppStatusResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class AppTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testStatus(): void + { + $result = $this->client->app->status(); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(AppStatusResponse::class, $result); + } +} diff --git a/tests/Services/BridgesTest.php b/tests/Services/BridgesTest.php new file mode 100644 index 0000000..214bdc4 --- /dev/null +++ b/tests/Services/BridgesTest.php @@ -0,0 +1,38 @@ +<?php + +namespace Tests\Services; + +use BeeperDesktop\Bridges\BridgeListResponse; +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class BridgesTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testList(): void + { + $result = $this->client->bridges->list(); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(BridgeListResponse::class, $result); + } +} diff --git a/tests/Services/Matrix/Bridges/AuthTest.php b/tests/Services/Matrix/Bridges/AuthTest.php new file mode 100644 index 0000000..fa3ba1c --- /dev/null +++ b/tests/Services/Matrix/Bridges/AuthTest.php @@ -0,0 +1,189 @@ +<?php + +namespace Tests\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListFlowsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthListLoginsResponse; +use BeeperDesktop\Matrix\Bridges\Auth\AuthWhoamiResponse; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class AuthTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testListFlows(): void + { + $result = $this->client->matrix->bridges->auth->listFlows('bridgeID'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(AuthListFlowsResponse::class, $result); + } + + #[Test] + public function testListLogins(): void + { + $result = $this->client->matrix->bridges->auth->listLogins('bridgeID'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(AuthListLoginsResponse::class, $result); + } + + #[Test] + public function testLogout(): void + { + $result = $this->client->matrix->bridges->auth->logout( + 'bcc68892-b180-414f-9516-b4aadf7d0496', + bridgeID: 'bridgeID' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testLogoutWithOptionalParams(): void + { + $result = $this->client->matrix->bridges->auth->logout( + 'bcc68892-b180-414f-9516-b4aadf7d0496', + bridgeID: 'bridgeID' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testStartLogin(): void + { + $result = $this->client->matrix->bridges->auth->startLogin( + 'qr', + bridgeID: 'bridgeID' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testStartLoginWithOptionalParams(): void + { + $result = $this->client->matrix->bridges->auth->startLogin( + 'qr', + bridgeID: 'bridgeID', + loginID: 'bcc68892-b180-414f-9516-b4aadf7d0496', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testSubmitCookies(): void + { + $result = $this->client->matrix->bridges->auth->submitCookies( + 'stepID', + bridgeID: 'bridgeID', + loginProcessID: 'loginProcessID', + body: ['foo' => 'string'], + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testSubmitCookiesWithOptionalParams(): void + { + $result = $this->client->matrix->bridges->auth->submitCookies( + 'stepID', + bridgeID: 'bridgeID', + loginProcessID: 'loginProcessID', + body: ['foo' => 'string'], + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testSubmitUserInput(): void + { + $result = $this->client->matrix->bridges->auth->submitUserInput( + 'stepID', + bridgeID: 'bridgeID', + loginProcessID: 'loginProcessID', + body: ['foo' => 'string'], + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testSubmitUserInputWithOptionalParams(): void + { + $result = $this->client->matrix->bridges->auth->submitUserInput( + 'stepID', + bridgeID: 'bridgeID', + loginProcessID: 'loginProcessID', + body: ['foo' => 'string'], + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testWaitForStep(): void + { + $result = $this->client->matrix->bridges->auth->waitForStep( + 'stepID', + bridgeID: 'bridgeID', + loginProcessID: 'loginProcessID' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testWaitForStepWithOptionalParams(): void + { + $result = $this->client->matrix->bridges->auth->waitForStep( + 'stepID', + bridgeID: 'bridgeID', + loginProcessID: 'loginProcessID' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertNotNull($result); + } + + #[Test] + public function testWhoami(): void + { + $result = $this->client->matrix->bridges->auth->whoami('bridgeID'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(AuthWhoamiResponse::class, $result); + } +} diff --git a/tests/Services/Matrix/Bridges/CapabilitiesTest.php b/tests/Services/Matrix/Bridges/CapabilitiesTest.php new file mode 100644 index 0000000..47d3402 --- /dev/null +++ b/tests/Services/Matrix/Bridges/CapabilitiesTest.php @@ -0,0 +1,39 @@ +<?php + +namespace Tests\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class CapabilitiesTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testRetrieve(): void + { + $result = $this->client->matrix->bridges->capabilities->retrieve( + 'bridgeID' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsArray($result); + } +} diff --git a/tests/Services/Matrix/Bridges/ContactsTest.php b/tests/Services/Matrix/Bridges/ContactsTest.php new file mode 100644 index 0000000..192394c --- /dev/null +++ b/tests/Services/Matrix/Bridges/ContactsTest.php @@ -0,0 +1,38 @@ +<?php + +namespace Tests\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Contacts\ContactListResponse; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class ContactsTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testList(): void + { + $result = $this->client->matrix->bridges->contacts->list('bridgeID'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(ContactListResponse::class, $result); + } +} diff --git a/tests/Services/Matrix/Bridges/RoomsTest.php b/tests/Services/Matrix/Bridges/RoomsTest.php new file mode 100644 index 0000000..f069dee --- /dev/null +++ b/tests/Services/Matrix/Bridges/RoomsTest.php @@ -0,0 +1,89 @@ +<?php + +namespace Tests\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewDmResponse; +use BeeperDesktop\Matrix\Bridges\Rooms\RoomNewGroupResponse; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class RoomsTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testCreateDm(): void + { + $result = $this->client->matrix->bridges->rooms->createDm( + 'identifier', + bridgeID: 'bridgeID' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(RoomNewDmResponse::class, $result); + } + + #[Test] + public function testCreateDmWithOptionalParams(): void + { + $result = $this->client->matrix->bridges->rooms->createDm( + 'identifier', + bridgeID: 'bridgeID', + loginID: 'bcc68892-b180-414f-9516-b4aadf7d0496', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(RoomNewDmResponse::class, $result); + } + + #[Test] + public function testCreateGroup(): void + { + $result = $this->client->matrix->bridges->rooms->createGroup( + 'groupType', + bridgeID: 'bridgeID' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(RoomNewGroupResponse::class, $result); + } + + #[Test] + public function testCreateGroupWithOptionalParams(): void + { + $result = $this->client->matrix->bridges->rooms->createGroup( + 'groupType', + bridgeID: 'bridgeID', + loginID: 'bcc68892-b180-414f-9516-b4aadf7d0496', + avatar: ['url' => 'url'], + disappear: ['timer' => 0, 'type' => 'type'], + name: ['name' => 'name'], + parent: (object) [], + participants: ['string'], + roomID: 'room_id', + topic: ['topic' => 'topic'], + type: 'channel', + username: 'username', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(RoomNewGroupResponse::class, $result); + } +} diff --git a/tests/Services/Matrix/Bridges/UsersTest.php b/tests/Services/Matrix/Bridges/UsersTest.php new file mode 100644 index 0000000..f0ecb93 --- /dev/null +++ b/tests/Services/Matrix/Bridges/UsersTest.php @@ -0,0 +1,64 @@ +<?php + +namespace Tests\Services\Matrix\Bridges; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Bridges\Users\UserResolveResponse; +use BeeperDesktop\Matrix\Bridges\Users\UserSearchResponse; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class UsersTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testResolve(): void + { + $result = $this->client->matrix->bridges->users->resolve( + 'identifier', + bridgeID: 'bridgeID' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(UserResolveResponse::class, $result); + } + + #[Test] + public function testResolveWithOptionalParams(): void + { + $result = $this->client->matrix->bridges->users->resolve( + 'identifier', + bridgeID: 'bridgeID', + loginID: 'bcc68892-b180-414f-9516-b4aadf7d0496', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(UserResolveResponse::class, $result); + } + + #[Test] + public function testSearch(): void + { + $result = $this->client->matrix->bridges->users->search('bridgeID'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(UserSearchResponse::class, $result); + } +} diff --git a/tests/Services/Matrix/Rooms/AccountDataTest.php b/tests/Services/Matrix/Rooms/AccountDataTest.php new file mode 100644 index 0000000..b87acab --- /dev/null +++ b/tests/Services/Matrix/Rooms/AccountDataTest.php @@ -0,0 +1,82 @@ +<?php + +namespace Tests\Services\Matrix\Rooms; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class AccountDataTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testRetrieve(): void + { + $result = $this->client->matrix->rooms->accountData->retrieve( + 'org.example.custom.room.config', + userID: '@alice:example.com', + roomID: '!726s6s6q:example.com', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testRetrieveWithOptionalParams(): void + { + $result = $this->client->matrix->rooms->accountData->retrieve( + 'org.example.custom.room.config', + userID: '@alice:example.com', + roomID: '!726s6s6q:example.com', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testUpdate(): void + { + $result = $this->client->matrix->rooms->accountData->update( + 'org.example.custom.room.config', + userID: '@alice:example.com', + roomID: '!726s6s6q:example.com', + body: ['custom_account_data_key' => 'custom_account_data_value'], + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testUpdateWithOptionalParams(): void + { + $result = $this->client->matrix->rooms->accountData->update( + 'org.example.custom.room.config', + userID: '@alice:example.com', + roomID: '!726s6s6q:example.com', + body: ['custom_account_data_key' => 'custom_account_data_value'], + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } +} diff --git a/tests/Services/Matrix/Rooms/EventsTest.php b/tests/Services/Matrix/Rooms/EventsTest.php new file mode 100644 index 0000000..9096bc8 --- /dev/null +++ b/tests/Services/Matrix/Rooms/EventsTest.php @@ -0,0 +1,53 @@ +<?php + +namespace Tests\Services\Matrix\Rooms; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Rooms\Events\EventGetResponse; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class EventsTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testRetrieve(): void + { + $result = $this->client->matrix->rooms->events->retrieve( + '$asfDuShaf7Gafaw:matrix.org', + roomID: '!636q39766251:matrix.org' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(EventGetResponse::class, $result); + } + + #[Test] + public function testRetrieveWithOptionalParams(): void + { + $result = $this->client->matrix->rooms->events->retrieve( + '$asfDuShaf7Gafaw:matrix.org', + roomID: '!636q39766251:matrix.org' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(EventGetResponse::class, $result); + } +} diff --git a/tests/Services/Matrix/Rooms/StateTest.php b/tests/Services/Matrix/Rooms/StateTest.php new file mode 100644 index 0000000..968d320 --- /dev/null +++ b/tests/Services/Matrix/Rooms/StateTest.php @@ -0,0 +1,66 @@ +<?php + +namespace Tests\Services\Matrix\Rooms; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class StateTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testRetrieve(): void + { + $result = $this->client->matrix->rooms->state->retrieve( + 'state_key', + roomID: '!636q39766251:example.com', + eventType: 'm.room.name' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsArray($result); + } + + #[Test] + public function testRetrieveWithOptionalParams(): void + { + $result = $this->client->matrix->rooms->state->retrieve( + 'state_key', + roomID: '!636q39766251:example.com', + eventType: 'm.room.name', + format: 'content', + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsArray($result); + } + + #[Test] + public function testList(): void + { + $result = $this->client->matrix->rooms->state->list( + '!636q39766251:example.com' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsList($result); + } +} diff --git a/tests/Services/Matrix/RoomsTest.php b/tests/Services/Matrix/RoomsTest.php new file mode 100644 index 0000000..330e193 --- /dev/null +++ b/tests/Services/Matrix/RoomsTest.php @@ -0,0 +1,57 @@ +<?php + +namespace Tests\Services\Matrix; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Rooms\RoomJoinResponse; +use BeeperDesktop\Matrix\Rooms\RoomNewResponse; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class RoomsTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testCreate(): void + { + $result = $this->client->matrix->rooms->create(); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(RoomNewResponse::class, $result); + } + + #[Test] + public function testJoin(): void + { + $result = $this->client->matrix->rooms->join('!monkeys:matrix.org'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(RoomJoinResponse::class, $result); + } + + #[Test] + public function testLeave(): void + { + $result = $this->client->matrix->rooms->leave('!nkl290a:matrix.org'); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } +} diff --git a/tests/Services/Matrix/Users/AccountDataTest.php b/tests/Services/Matrix/Users/AccountDataTest.php new file mode 100644 index 0000000..7381eb8 --- /dev/null +++ b/tests/Services/Matrix/Users/AccountDataTest.php @@ -0,0 +1,78 @@ +<?php + +namespace Tests\Services\Matrix\Users; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class AccountDataTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testRetrieve(): void + { + $result = $this->client->matrix->users->accountData->retrieve( + 'org.example.custom.config', + userID: '@alice:example.com' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testRetrieveWithOptionalParams(): void + { + $result = $this->client->matrix->users->accountData->retrieve( + 'org.example.custom.config', + userID: '@alice:example.com' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testUpdate(): void + { + $result = $this->client->matrix->users->accountData->update( + 'org.example.custom.config', + userID: '@alice:example.com', + body: ['custom_account_data_key' => 'custom_config_value'], + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } + + #[Test] + public function testUpdateWithOptionalParams(): void + { + $result = $this->client->matrix->users->accountData->update( + 'org.example.custom.config', + userID: '@alice:example.com', + body: ['custom_account_data_key' => 'custom_config_value'], + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertIsNotResource($result); + } +} diff --git a/tests/Services/Matrix/UsersTest.php b/tests/Services/Matrix/UsersTest.php new file mode 100644 index 0000000..f04e2a6 --- /dev/null +++ b/tests/Services/Matrix/UsersTest.php @@ -0,0 +1,40 @@ +<?php + +namespace Tests\Services\Matrix; + +use BeeperDesktop\Client; +use BeeperDesktop\Core\Util; +use BeeperDesktop\Matrix\Users\UserGetProfileResponse; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +/** + * @internal + */ +#[CoversNothing] +final class UsersTest extends TestCase +{ + protected Client $client; + + protected function setUp(): void + { + parent::setUp(); + + $testUrl = Util::getenv('TEST_API_BASE_URL') ?: 'http://127.0.0.1:4010'; + $client = new Client(accessToken: 'My Access Token', baseUrl: $testUrl); + + $this->client = $client; + } + + #[Test] + public function testRetrieveProfile(): void + { + $result = $this->client->matrix->users->retrieveProfile( + '@alice:example.com' + ); + + // @phpstan-ignore-next-line method.alreadyNarrowedType + $this->assertInstanceOf(UserGetProfileResponse::class, $result); + } +} From a7a46fc8567c09e580100ca462839186a98e94a7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 20:21:33 +0000 Subject: [PATCH 45/48] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index b63d20d..62239e7 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 72 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-de1370e6a3183044fa135a886d2ee8f779d5e86228cdbd503d553b4c13cc7cbe.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-8ba2755730c4180ec88f92a300948445d7917898abfc912ca3fa6adc766a7520.yml openapi_spec_hash: 30b435d7585d8b6951610e7147369779 -config_hash: 683b13ea6fb6aa9d6b1b8814cca24f1c +config_hash: a53888715ed00d433e5a5dafab9f7b9f From c584539e33f459fab955d5a7b09d8a4922acfd5e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 20:32:42 +0000 Subject: [PATCH 46/48] codegen metadata --- .stats.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 62239e7..8fcd9ea 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 72 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-8ba2755730c4180ec88f92a300948445d7917898abfc912ca3fa6adc766a7520.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-6cdaa898dcc095d108f684dd847bc19da7156b0a09ffb4cac2e613c53a0647e5.yml openapi_spec_hash: 30b435d7585d8b6951610e7147369779 -config_hash: a53888715ed00d433e5a5dafab9f7b9f +config_hash: 33cb47306fb0333ac538d5db65e8d52f From 9beaf921fb4fb0567d4cbf03c6ce17a686277b59 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 20:38:52 +0000 Subject: [PATCH 47/48] Update Desktop API docs and SDK config --- .stats.yml | 6 +++--- src/Client.php | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.stats.yml b/.stats.yml index 8fcd9ea..a6a4fc8 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 72 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/beeper/beeper-desktop-api-6cdaa898dcc095d108f684dd847bc19da7156b0a09ffb4cac2e613c53a0647e5.yml -openapi_spec_hash: 30b435d7585d8b6951610e7147369779 -config_hash: 33cb47306fb0333ac538d5db65e8d52f +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/src/Client.php b/src/Client.php index 9595110..d09e4e1 100644 --- a/src/Client.php +++ b/src/Client.php @@ -34,42 +34,42 @@ class Client extends BaseClient /** * @api */ - public AppService $app; + public AccountsService $accounts; /** * @api */ - public AccountsService $accounts; + public BridgesService $bridges; /** * @api */ - public BridgesService $bridges; + public ChatsService $chats; /** * @api */ - public MatrixService $matrix; + public MessagesService $messages; /** * @api */ - public ChatsService $chats; + public AssetsService $assets; /** * @api */ - public MessagesService $messages; + public InfoService $info; /** * @api */ - public AssetsService $assets; + public AppService $app; /** * @api */ - public InfoService $info; + public MatrixService $matrix; /** * @api @@ -139,14 +139,14 @@ public function __construct( options: $options ); - $this->app = new AppService($this); $this->accounts = new AccountsService($this); $this->bridges = new BridgesService($this); - $this->matrix = new MatrixService($this); $this->chats = new ChatsService($this); $this->messages = new MessagesService($this); $this->assets = new AssetsService($this); $this->info = new InfoService($this); + $this->app = new AppService($this); + $this->matrix = new MatrixService($this); $this->raw = new BeeperDesktopClientRawService($this); $this->beeperDesktopClientService = new BeeperDesktopClientService($this); } From ad9c46158393321ee06676fcfa167ede6f95e73e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 20:39:32 +0000 Subject: [PATCH 48/48] release: 5.0.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 49 +++++++++++++++++++++++++++++++++++ src/Version.php | 2 +- 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1332969..8e76abb 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.1" + ".": "5.0.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..18ca859 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,49 @@ +# Changelog + +## 5.0.0 (2026-05-16) + +Full Changelog: [v0.0.1...v5.0.0](https://github.com/beeper/desktop-api-php/compare/v0.0.1...v5.0.0) + +### Features + +* **api:** add network, bridge fields to accounts ([8b25044](https://github.com/beeper/desktop-api-php/commit/8b250446d8d538fc1027c9df483f07034049e302)) +* **api:** api update ([d5d8954](https://github.com/beeper/desktop-api-php/commit/d5d89549d1dcdb03ebd079062c25917f76de162e)) +* **api:** api update ([48ca998](https://github.com/beeper/desktop-api-php/commit/48ca99875d9640e728922eab3eed6988fcd4ea14)) +* **api:** api update ([e098615](https://github.com/beeper/desktop-api-php/commit/e0986159d91fbd76d8647de9e2f7e2f1aedb071f)) +* **api:** api update ([fe6b606](https://github.com/beeper/desktop-api-php/commit/fe6b606f1e40643b6f81a68bfbf467653d070a6a)) +* **api:** api update ([f813329](https://github.com/beeper/desktop-api-php/commit/f8133290552840e3723a0f67371a4481039c5ac6)) +* **api:** api update ([1c754b3](https://github.com/beeper/desktop-api-php/commit/1c754b319cf35db0357cd97d9713119b78f70fc5)) +* **api:** manual updates ([46dbc09](https://github.com/beeper/desktop-api-php/commit/46dbc095defeac9aa95e41cd668e883fcd20bea9)) +* **api:** update via SDK Studio ([1c4d0e7](https://github.com/beeper/desktop-api-php/commit/1c4d0e7cb265c3bfcca18b886ec84d25eb7154d2)) +* **api:** update via SDK Studio ([e372296](https://github.com/beeper/desktop-api-php/commit/e372296e9885f6bb33819a22d29e92ac725395f1)) +* support setting headers via env ([91d9d0e](https://github.com/beeper/desktop-api-php/commit/91d9d0e7e5e35f90aa52187308f366ceb438080b)) + + +### Bug Fixes + +* **client:** properly generate file params ([44ea2d6](https://github.com/beeper/desktop-api-php/commit/44ea2d6f7210b88dd61b764242e7a68254f07efb)) +* **client:** resolve serialization issue with unions and enums ([7d947c2](https://github.com/beeper/desktop-api-php/commit/7d947c2190514f5039947136a1e795e69069d42b)) +* guzzle requires special handling to enable streaming ([3a41088](https://github.com/beeper/desktop-api-php/commit/3a41088103be62e91f609605f2b5e994921a68dc)) +* populate enum-typed properties with enum instances ([8c3b6fc](https://github.com/beeper/desktop-api-php/commit/8c3b6fc3be27e61cfb5556fab51f29bff5eae2e6)) +* revert enum parsing change that lead to unconditional failure ([82c146a](https://github.com/beeper/desktop-api-php/commit/82c146af6213f707f29059eed0d9061aa0555c4b)) + + +### Chores + +* **internal:** codegen related update ([297da59](https://github.com/beeper/desktop-api-php/commit/297da598fb4ba18fec57a63e461e4316f3d6e641)) +* **internal:** tweak CI branches ([d3967d0](https://github.com/beeper/desktop-api-php/commit/d3967d0433e63e905f0d9699da709a7544ec12db)) +* **internal:** update multipart form array serialization ([05282bb](https://github.com/beeper/desktop-api-php/commit/05282bbbaad46dceff167998b75e34a778f42a24)) +* **internal:** upgrade phpunit ([958db57](https://github.com/beeper/desktop-api-php/commit/958db5719fcca4f33c8b9c4796e34b8a3c5a8d91)) +* **test:** do not count install time for mock server timeout ([344cf76](https://github.com/beeper/desktop-api-php/commit/344cf76b4dc4c254d6c380f035e8b6d2d86fb138)) +* **tests:** bump steady to v0.19.4 ([5ead500](https://github.com/beeper/desktop-api-php/commit/5ead500c3d450d125dee608bc6ec0054e6928e15)) +* **tests:** bump steady to v0.19.5 ([1987ab0](https://github.com/beeper/desktop-api-php/commit/1987ab0fcc91f0bebfdf55a94fd5b6c59f3658e3)) +* **tests:** bump steady to v0.19.6 ([5299bea](https://github.com/beeper/desktop-api-php/commit/5299bea39412364752a5a21800bc9e5837cbce81)) +* **tests:** bump steady to v0.19.7 ([356dd2b](https://github.com/beeper/desktop-api-php/commit/356dd2b76fe8549a90e60013ad72e3fd5683e3cd)) +* **tests:** bump steady to v0.20.1 ([9a809f7](https://github.com/beeper/desktop-api-php/commit/9a809f782c368dbed079b96555a27f76f39a9b42)) +* **tests:** bump steady to v0.20.2 ([71daf35](https://github.com/beeper/desktop-api-php/commit/71daf3588b2f471df63c4070b121e8c5587e5727)) +* **tests:** bump steady to v0.22.1 ([192de54](https://github.com/beeper/desktop-api-php/commit/192de547707b52e2d5f60984af9d2c153bef2060)) + + +### Refactors + +* **tests:** switch from prism to steady ([b2a0994](https://github.com/beeper/desktop-api-php/commit/b2a099467ced88b63d36ae05aa4db7da5b5c64c8)) diff --git a/src/Version.php b/src/Version.php index fa38b72..16c7e53 100644 --- a/src/Version.php +++ b/src/Version.php @@ -5,5 +5,5 @@ namespace BeeperDesktop; // x-release-please-start-version -const VERSION = '0.0.1'; +const VERSION = '5.0.0'; // x-release-please-end